【问题标题】:React Native component not re-rendering on state changeReact Native 组件不会在状态更改时重新渲染
【发布时间】:2020-03-10 12:20:50
【问题描述】:

在收到更改其状态的新道具后,我无法重新渲染组件。我对 React Native 和使用钩子都很陌生,所以请多多包涵。这是有问题的组件:

function AreaChart(timeScale) {

  const width = Dimensions.get('window').width;
  const height = Dimensions.get('window').height;
  const [areaChartJS, setAreaChartJS] = useState(chartJS.areaChart(width, timeScale.timeScale));

  useEffect(() => {
    console.log(timeScale.timeScale);
    setAreaChartJS(chartJS.areaChart(width, timeScale.timeScale));
  }, [areaChartJS, timeScale]);

  return(
    <View>
      <WebView
        originWhitelist={['*']}
        useWebKit={true}
        source={{ html: areaChartHtml }}
        domStorageEnabled={true}
        javaScriptEnabled={true}
        style={styles.WebViewStyle}
        injectedJavaScript={areaChartJS}
      />
      <Text>{timeScale.timeScale}</Text>
    </View>
  );
}

这需要一些解释。我正在使用仅为网络设计的图表库,因此我必须在此处使用 WebView 才能呈现它。 areaChartHtml 和 areaChartJS 是注入到 WebView 中的 HTML 和 JS 代码,因为它们都是本地的。这些都是 WebView 解析和呈现的字符串。我在另一个名为 chartJS 的文件中有 JS 代码,我在传递设备宽度和 timeScale 时调用该文件,以便基于这些变量动态呈现图表。

问题是,在更改 timeScale 后,组件不会重新渲染,并在初始渲染期间继续使用从父组件传递的初始 timeScale。在 useEffect 钩子中,我正在记录 timeScale 并且我得到了正确的值,但是即使我使用新的 timeScale 道具通过 setAreaChartJS 函数更改状态,也不会触发重新渲染。 WebView 下的&lt;Text&gt; 元素也显示了正确的 timeScale 实时值,甚至从外部 chartJS 文件中记录它也显示了正确的值,但是新的 JS 代码没有被注入到 WebView 中。 &lt;Text&gt; 使用新值更新的事实告诉我组件 正在 重新渲染,但 WebView 没有从状态中拉出新的 areaChartJS。

当组件完全卸载并再次安装时,timeScale 会正确注册,并且图表会相应地呈现。在不完全重新安装组件的情况下如何实现这一点?

【问题讨论】:

    标签: reactjs react-native react-hooks


    【解决方案1】:

    我已经设法通过在 WebView 上放置 ref 并在 useEffect 中调用其 .reload() 方法来获得所需的行为。我不知道 WebView 的内部工作原理,但我认为它会将注入的 JS 的初始值保存在某处,并且即使正在重新渲染组件也不会注入新值,除非您以这种方式强制重新加载。这是组件现在的样子:

    function AreaChart(timeScale) {
    
      const width = Dimensions.get('window').width;
      const height = Dimensions.get('window').height;
      const [areaChartJS, setAreaChartJS] = useState(chartJS.areaChart(width, timeScale.timeScale));
      const [currTimeScale, setCurrTimeScale] = useState('1h');
    
      useEffect(() => {
        setAreaChartJS(chartJS.areaChart(width, timeScale.timeScale));
        if (currTimeScale !== timeScale.timeScale) {
          WebViewRef.reload();
          setCurrTimeScale(timeScale.timeScale);
        }
      }, [timeScale]);
    
      return(
        <View style={{flex: 1, height: 300}}>
          <WebView
            ref={WVref => (WebViewRef = WVref)}
            originWhitelist={['*']}
            useWebKit={true}
            source={{ html: areaChartHtml }}
            domStorageEnabled={true}
            javaScriptEnabled={true}
            style={styles.WebViewStyle}
            injectedJavaScript={areaChartJS}
          />
        </View>
      );
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-02-27
      • 2018-03-17
      • 2018-12-12
      • 2020-03-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多