我有一个外部(组件),可观察对象,我想监听的变化。当对象更新时,它会发出更改事件,然后我希望在检测到任何更改时重新呈现组件。

使用顶级React。渲染这是可能的,但在组件中它不起作用(这是有意义的,因为渲染方法只返回一个对象)。

下面是一个代码示例:

export default class MyComponent extends React.Component {

  handleButtonClick() {
    this.render();
  }

  render() {
    return (
      <div>
        {Math.random()}
        <button onClick={this.handleButtonClick.bind(this)}>
          Click me
        </button>
      </div>
    )
  }
}

在内部单击按钮会调用this.render(),但这并不是真正导致呈现发生的原因(您可以在操作中看到这一点,因为由{Math.random()}创建的文本没有改变)。但是,如果我简单地调用this.setState()而不是this.render(),它就可以正常工作。

所以我想我的问题是:React组件需要有状态才能渲染吗?是否有一种方法可以在不改变状态的情况下强制组件按需更新?


当前回答

另一种方法是调用setState和preserve state:

this.setState(prevState=>({...上一页状态}));

其他回答

你可以有几种方法:

1. 使用forceUpdate()方法:

使用forceUpdate()方法时可能会出现一些故障。一个例子是它忽略shouldComponentUpdate()方法,并将重新呈现视图,而不管shouldComponentUpdate()是否返回false。因此,应该尽可能避免使用forceUpdate()。

2. 通过这个。状态转换为setState()方法

下面这行代码克服了前面例子中的问题:

this.setState(this.state);

实际上,所有这些都是用触发重新渲染的当前状态覆盖当前状态。这仍然不一定是最好的方法,但它确实克服了使用forceUpdate()方法时可能遇到的一些故障。

在类组件中,可以调用this.forceUpdate()来强制渲染。

文档:https://facebook.github.io/react/docs/component-api.html

在函数组件中,没有等效的forceUpdate,但您可以通过useState钩子设计一种强制更新的方法。

我发现最好避免使用forceUpdate()。强制重新呈现的一种方法是在临时外部变量上添加render()依赖项,并在需要时更改该变量的值。

下面是一个代码示例:

class Example extends Component{
   constructor(props){
      this.state = {temp:0};

      this.forceChange = this.forceChange.bind(this);
   }

   forceChange(){
      this.setState(prevState => ({
          temp: prevState.temp++
      })); 
   }

   render(){
      return(
         <div>{this.state.temp &&
             <div>
                  ... add code here ...
             </div>}
         </div>
      )
   }
}

当你需要强制重新渲染时,调用this.forceChange()。

使用useEffect作为componentDidMount, componentDidUpdate和componentWillUnmount的组合,如React文档中所述。

要像componentDidMount一样工作,你需要像这样设置你的useEffect:

  useEffect(() => console.log('mounted'), []);

第一个参数是一个回调,它将根据第二个参数(一个值数组)触发。如果第二个参数中的任何值发生了变化,您在useEffect中定义的回调函数将被触发。

然而,在我所展示的示例中,我传递了一个空数组作为第二个参数,这将永远不会被更改,因此回调函数将在组件挂载时调用一次。

这是对useEffect的总结。如果不是空值,而是有一个参数,比如:

 useEffect(() => {

  }, [props.lang]);

这意味着每次道具。Lang改变,你的回调函数将被调用。useEffect实际上不会重新渲染你的组件,除非你在回调函数中管理一些状态,这些状态可能会触发重新渲染。

如果你想要触发一个重新渲染,你的渲染函数需要在你的useEffect中更新一个状态。

例如,在这里,渲染函数开始显示英语作为默认语言,在我的使用效果中,我在3秒后改变了语言,所以渲染被重新渲染并开始显示“西班牙语”。

function App() {
  const [lang, setLang] = useState("english");

  useEffect(() => {
    setTimeout(() => {
      setLang("spanish");
    }, 3000);
  }, []);

  return (
    <div className="App">
      <h1>Lang:</h1>
      <p>{lang}</p>
    </div>
  );
}

当你想要两个React组件进行通信时,它们不受关系(父子关系)的约束,建议使用Flux或类似的架构。

您要做的是监听可观察组件存储的变化,该存储保存模型及其接口,并将导致呈现变化的数据保存为MyComponent中的状态。当存储推送新数据时,更改组件的状态,这会自动触发呈现。

通常你应该尽量避免使用forceUpdate()。从文档中可以看到:

通常情况下,你应该尽量避免使用forceUpdate(),只从这个中读取。道具和这个。render()中的状态。这使您的应用程序更加简单和高效