最新消息:20190717 VPS服务器:Vultr新加坡,WordPress主题:大前端D8,统一介绍入口:关于

【已解决】Reactjs中如何在Component的外部改变和获取state状态值

ReactJS crifan 81浏览 0评论
折腾:
【未解决】AntD Pro中支持剧本剧本编写时拖动排序单个对话
期间,需要对于
class DragSortingTable extends 
React.Component
 {
  state = {
    data: [
    ]
  }
}

  DragableDialogTable = DragDropContext(HTML5Backend)(DragSortingTable)

render() {
                <this.DragableDialogTable />
}
这种情况,想要在DragSortingTable的外部,去更新内部state的值
以实现可以在新增一行后,把新的列表的值,传递到可拖动去改变列表元素排序的内部
同时还需要,对于已经改变了排序的结果的值,在外部需要获取能
这样每次新增之前,才能用最新的被拖动排序后的列去新增
或许直接用props参数即可?
react js change state from outside
reactjs – Set React component state from outside of component – Stack Overflow
javascript – setState/use State in external function react – Stack Overflow
reactjs – Update react component without parent outside of it – Stack Overflow
Accessing Component Methods and State from Outside React
Question: how to just update parentless component outside of it? · Issue #5906 · facebook/react · GitHub
reactjs – Update react component without parent outside of it – Stack Overflow
好像是用componentWillReceiveProps更合适
去试试
但是此处突然发现,此处还没发写成:
// DragableDialogTable = DragDropContext(HTML5Backend)(DragSortingTable)
DragableDialogTable = DragDropContext(HTML5Backend)(DragSortingTable itemList={demoItemList})
因为此处只是class DragSortingTable的调用而不是元素:
<DragSortingTable />
的调用,没法这么传递props
那貌似只能去试试:
直接给class DragSortingTable添加函数了
但是貌似是class的instance的函数,也没法加static的函数啊?
这样就没法修改每个instance的内部的state了?
突然想到了:
还是直接把DragSortingTable合并到当前的业务逻辑中,就可以了。
但是发现好像也不对,还是由于是class,没法直接直接合并
否则自己没法render自己
自己试试,能否添加额外函数,实现state的list的同步
或者加上额外的外部的全局变量去实现数据的同步
现在问题变成了:如何更新component class内部的state
react js change component class state
javascript – REACTJS: Change state in another class – Stack Overflow
javascript – ReactJS change state of another class from child – Stack Overflow
另外看到此处的代码中的DragDropContext的定义:
/**
 * Wrap the root component of your application with DragDropContext decorator to set up React DnD.
 * This lets you specify the backend, and sets up the shared DnD state behind the scenes.
 * @param backendFactory The DnD backend factory
 * @param backendContext The backend context
 */
export declare function DragDropContext(backendFactory: BackendFactory, backendContext?: any): <TargetClass extends 
React.ComponentClass
<any> | React.StatelessComponent<any>>(DecoratedComponent: TargetClass) => TargetClass & ContextComponent<any>;
感觉是:
或许此处可以避开DragDropContext
因为此处不是root的element
然后希望不用传递TargetClass的方式,而是直接调用component,这样就可以传递参数和获取instance的state了。
去看看
https://github.com/react-dnd/react-dnd
中,是否一定要使用这种方式去调用
http://react-dnd.github.io/react-dnd/examples-sortable-simple.html
是我们需要的:
找了一下,终于找到这个example的代码了:
https://github.com/react-dnd/react-dnd
-》
react-dnd/react-dnd: Drag and Drop for React
-》
react-dnd/packages/documentation at master · react-dnd/react-dnd
-》
react-dnd/packages/documentation/examples at master · react-dnd/react-dnd
-》
react-dnd/packages/documentation/examples/04 Sortable at master · react-dnd/react-dnd
react-dnd/packages/documentation/examples/04 Sortable/Simple at master · react-dnd/react-dnd
去参考看看代码:
git clone 
https://github.com/react-dnd/react-dnd.git
然后出错:
➜  react-dnd git:(master) npm install && npm start
npm WARN deprecated istanbul-lib-hook@1.2.1: 1.2.0 should have been a major version bump

> fsevents@1.2.4 install /Users/crifan/dev/dev_src/ReactJS/react-dnd/node_modules/fsevents
> node install

[fsevents] Success: "/Users/crifan/dev/dev_src/ReactJS/react-dnd/node_modules/fsevents/lib/binding/Release/node-v64-darwin-x64/fse.node" already installed
Pass --update-binary to reinstall or --build-from-source to recompile

> husky@0.14.3 install /Users/crifan/dev/dev_src/ReactJS/react-dnd/node_modules/husky
> node ./bin/install.js

husky
setting up Git hooks
done

npm WARN prepublish-on-install As of npm@5, `prepublish` scripts are deprecated.
npm WARN prepublish-on-install Use `prepare` for build steps and `prepublishOnly` for upload-only.
npm WARN prepublish-on-install See the deprecation note in `npm help scripts` for more information.

> react-dnd-master@ prepublish /Users/crifan/dev/dev_src/ReactJS/react-dnd
> npm test


> react-dnd-master@ test /Users/crifan/dev/dev_src/ReactJS/react-dnd
> run-s lint build test_modules jest:cov


> react-dnd-master@ lint /Users/crifan/dev/dev_src/ReactJS/react-dnd
> tslint "packages/**/*.{ts,tsx}" -e "**/{lib,node_modules}/**"

internal/modules/cjs/loader.js:596
    throw err;
    ^

Error: Cannot find module 'typescript'
    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:594:15)
    at Function.Module._load (internal/modules/cjs/loader.js:520:25)
    at Module.require (internal/modules/cjs/loader.js:650:17)
    at require (internal/modules/cjs/helpers.js:20:18)
    at Object.<anonymous> (/Users/crifan/dev/dev_src/ReactJS/react-dnd/node_modules/tslint/lib/linter.js:22:10)
    at Module._compile (internal/modules/cjs/loader.js:702:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:713:10)
    at Module.load (internal/modules/cjs/loader.js:612:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:551:12)
    at Function.Module._load (internal/modules/cjs/loader.js:543:3)
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! react-dnd-master@ lint: `tslint "packages/**/*.{ts,tsx}" -e "**/{lib,node_modules}/**"`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the react-dnd-master@ lint script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/crifan/.npm/_logs/2018-08-06T05_55_53_490Z-debug.log
ERROR: "lint" exited with 1.
npm ERR! Test failed.  See above for more details.
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! react-dnd-master@ prepublish: `npm test`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the react-dnd-master@ prepublish script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/crifan/.npm/_logs/2018-08-06T05_55_53_594Z-debug.log
重新试试
结果npm install出错
算了。
只是去看代码,不运行demo了。
看了demo代码,也不是很容易懂。
刚看懂一点,好像是:
Container
只要用了:
@DragDropContext(HTML5Backend)
后,就可以正常的被别人调用了:
<Container />
那此处也去试试是否可以这么用
@DragDropContext(HTML5Backend)
class DragSortingTable extends 
React.Component
 {
  ...
}

    render() {
        return (
              <DragSortingTable
                itemList={this.demoItemList}
              />
真的可以。
-》那么接下来,就容易改变list,然后传入新的list了。
然后期间遇到:
【未解决】Reactjs中传入属性变化后componentWillReceiveProps不工作没有调用
折腾:
【未解决】Reactjs中如何在Component的外部改变和获取state状态值
期间,
已经用代码:
@DragDropContext(HTML5Backend)
class DragSortingTable extends 
React.Component
 {
  state = {
    itemList: [],
  }

  constructor(props){
    super(props)
    console.log("DragSortingTable constructor: props=", props)

    console.log("this.props.itemList=", this.props.itemList)

    this.state.itemList = this.props.itemList;
  }

  componentWillReceiveProps(nextProps){
    console.log("DragSortingTable componentWillReceiveProps: nextProps=", nextProps)
    console.log("this.props.itemList=", this.props.itemList)
    if (this.props.itemList) {
      this.setState({itemList: this.props.itemList})
      console.log("updated this.state.itemList=", this.state.itemList)
    }
  }

  components = {
    body: {
      row: DragableBodyRow,
    },
  }

  moveRow = (dragIndex, hoverIndex) => {
    const { itemList } = this.state;
    const dragRow = itemList[dragIndex];

    this.setState(
      update(this.state, {
        itemList: {
          $splice: [[dragIndex, 1], [hoverIndex, 0, dragRow]],
        },
      }),
    );
  }

  render() {
    console.log("DragSortingTable render: this.state.itemList=", this.state.itemList)

    return (
      <Table
        columns={columns}
        dataSource={this.state.itemList}
        components={
this.components
}
        onRow={(record, index) => ({
          index,
          moveRow: this.moveRow,
        })}
      />
    );
  }
}

@connect(({ loading, script, topic }) => ({
  submitting: loading.effects['script/submitRegularForm'],
  script,
  topic,
}))
@Form.create()
export default class ScriptCreate extends PureComponent {
  。。。

  handleAddDialog(){
    console.log("handleAddDialog")

    const curItemList = this.state.dialogList
    let newItemList = curItemList

    const curItemNum = curItemList.length
    const newItemNum = curItemNum + 1
    let newDialog = {
      key: `${newItemNum}`,
      speakerOrSong: `new speaker ${newItemNum}`,
      contentOrAddress: `new content ${newItemNum}`,
    }
    console.log("newDialog=", newDialog)

    newItemList.push(newDialog)
    console.log("newItemList=", newItemList)

    this.setState({ dialogList: newItemList})
    console.log("this.state.dialogList=", this.state.dialogList)
  }


    render() {
        return (
              <DragSortingTable
                itemList={this.state.dialogList}
              />
实现了,当点击添加按钮时,去新增一行,且用
this.setState({ dialogList: newItemList})
更新了state,但是DragSortingTable中的componentWillReceiveProps却没运行
react  props changed componentWillReceiveProps not called
reactjs – componentWillReceiveProps is not called on redux props change – Stack Overflow
* if its not receiving a new props object from the redux store
Props change does not re render · Issue #17 · uberVU/react-guide
`componentWillReceiveProps()` does not trigger for new context changes · Issue #5756 · facebook/react
猜测是此处用了redux而导致此处state变化了,但是componentWillReceiveProps也没有运行
如何解决呢?
想起来别人提起来的,强制刷新,试试:
this.forceUpdate()
就可以了。
【总结】
当reactjs使用了redux,则会导致setState后,子元素中的state变量变化了,但是子元素中的componentWillReceiveProps也不允许,从而无法实现刷新显示的效果
解决办法是,对于父元素中,setState后,加上:
this.forceUpdate()
即可强制刷新。则字元素也就正常了。

转载请注明:在路上 » 【已解决】Reactjs中如何在Component的外部改变和获取state状态值

发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
20 queries in 0.125 seconds, using 9.37MB memory