React(mobx)观察者组件render()在可观察变化时不调用

时间:2021-01-06 07:44:30

标签: javascript reactjs mobx

在以下示例代码中,unfinishedTodoCount(在LoadContent组件下)未更新TODO项目时未更新。

我在 TodoListView 的渲染方法中取消了 unfinishedTodoCount 的引用,所以我认为它必须由 mobx 跟踪。

(我使用“触发渲染”按钮强制 render() 更新 unfinishedTodoCount 值。)

问题:那么,为什么当 render() 发生变化时 mobx 不会触发 unfinishedTodoCount

注意事项:我想知道 props.children() 是否异步运行,因此 mobx 无法捕获取消引用。

(解决方案:可以通过在代码中取消注释行来应用各种解决方案。)

// Uncomment following so render() will be called when unfinishedTodoCount changes.
//@observer
class LoadContent extends React.Component {
  render() {
    console.log("rendering LoadContent");
    return (
      <div>
        {this.props.children({
          // ...this.props,
        })}
      </div>
    );
  }
}
    @observer
    class TodoListView extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          triggerRender: false
        };
      }
      render() {
        console.log("rendering TodoListView");
        // Uncomment following so render() will be called when unfinishedTodoCount changes.
        //let todoCount = this.props.todoList.unfinishedTodoCount;
        //console.log(todoCount);
        return (
          <div>
            <input
              type="Button"
              onClick={() =>
                this.setState({ triggerRender: !this.state.triggerRender })
              }
              value="Trigger rendering"
            />
            <ul>
              {this.props.todoList.todos.map((todo) => (
                <TodoView todo={todo} key={todo.id} />
              ))}
            </ul>
            <div>
              {/* Uncomment following so render() will be called when unfinishedTodoCount changes. */
              /* {(() => (
                  <div>Tasks left: {this.props.todoList.unfinishedTodoCount}</div>
                ))()} */}
              <LoadContent>
                {() => (
                  <div>Tasks left: {this.props.todoList.unfinishedTodoCount}</div>
                )}
              </LoadContent>
            </div>
          </div>
        );
      }
    }

完整的源代码在这里; https://codesandbox.io/s/simple-mobx-todolist-forked-hep3t?file=/index.js

1 个答案:

答案 0 :(得分:0)

我认为组件 render() 被异步调用(但组件是按预期同步呈现的)根据我的概念证明,因此 mobx 无法跟踪组件中的取消引用。 >

概念证明:组件称为异步。

我在 LoadContent 之后添加了一个 console.log() 调用,并在 LoadContent 中的 console.log() 之前调用了它。

<LoadContent>
{() => (
  <div>Tasks left: {this.props.todoList.unfinishedTodoCount}</div>
)}
</LoadContent>
{(()=>{console.log("after load content")})()}
rendering TodoListView 
*after load content* 
rendering LoadContent

(这里有完整的源代码;https://codesandbox.io/s/simple-mobx-todolist-forked-hep3t?file=/index.js

解决方案:我们可以对子组件使用@observer 装饰器,或者在父组件的 render() 之前访问那些可观察变量。

实际上,passing renderable callbacks to components 的警告也在以下文档中说明;

<块引用>

这里值得注意的警告是将可渲染的回调传递给 React 组件,以下面的例子为例:

const MyComponent = observer(({ message }) => <某个容器 标题 = {() => {message.title}} /> )

message.title = "Bar" 乍一看这里似乎一切正常, 除了实际上不是由 MyComponent 呈现的(其中 有一个跟踪渲染),但由 SomeContainer。所以要确保 SomeContainer 的标题正确响应新的 message.title, SomeContainer 也应该是观察者。如果 SomeContainer 来了 从外部库中,您也可以通过将 div 包装在其 自己的基于无状态观察者的组件,并在 回调:

const MyComponent = observer(({ message }) => <某个容器 标题 = {() => } /> )

const TitleRenderer = observer(({ message }) => {message.title}} )

message.title = "酒吧" https://doc.ebichu.cc/mobx/best/react.html