如何从渲染器访问在`useEffect`钩子中计算的值

时间:2021-01-18 21:36:55

标签: react-native react-hooks use-effect

我正在开发一个带有功能组件的 React-Native 项目。

这是一个非常简单的屏幕,用于呈现计算结果列表。由于我需要计算只被调用一次,所以我把它放在 useEffect 钩子里。

import {doCalculation} from '../util/helper'

const MyScreen = ({navigation}) => {
   useEffect(() => {
     // I call a function from a helper module here. 
     // The result is a list of object.
     const result = doCalculation();

     // eslint-disable-next-line
  }, []);

  // renderer
  return (
      <View> 
        // Problem is 'result' is not accessible here, but I need to render it here
        {result.map(item=> <Text key={item.id}> {item.value} </Text>)}
      </View>
  )
}

export default MyScreen;

如您所见,我已调用 doCalculation() 以获取 result 内的 useEffect 钩子。我的问题是如何在 return 部分呈现结果?由于 result 是在钩子内部计算的,因此无法在渲染器中访问。

附言将 const result = doCalculation() 移出 useEffect 钩子不是一个选项,因为我只需要调用一次计算。

4 个答案:

答案 0 :(得分:0)

利用useState保存计算结果,然后使用return里面的变量。见https://reactjs.org/docs/hooks-state.html

答案 1 :(得分:0)

代码片段:

<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet"/>
<div class="container" id="container">
    <div class="scroll-wrapper">
        <div class="scroll-container" id="scroll-container">
            <ul class="list-inline text-white text-center">
            
                <li class="list-inline-item" style="width: 200px;">
                    <div class="py-5 bg-dark"><h1 class="py-5">1</h1></div>
                </li>
                <li class="list-inline-item" style="width: 400px;">
                    <div class="py-5 bg-dark"><h1 class="py-5">2</h1></div>
                </li>
                <li class="list-inline-item" style="width: 300px;">
                    <div class="py-5 bg-dark"><h1 class="py-5">3</h1></div>
                </li>
                <li class="list-inline-item" style="width: 150px;">
                    <div class="py-5 bg-dark"><h1 class="py-5">4</h1></div>
                </li>
                <li class="list-inline-item" style="width: 250px;">
                    <div class="py-5 bg-dark"><h1 class="py-5">5</h1></div>
                </li>
                <li class="list-inline-item" style="width: 300px;">
                    <div class="py-5 bg-dark"><h1 class="py-5">6</h1></div>
                </li>
                <li class="list-inline-item" style="width: 200px;">
                    <div class="py-5 bg-dark"><h1 class="py-5">7</h1></div>
                </li>
                <li class="list-inline-item" style="width: 400px;">
                    <div class="py-5 bg-dark"><h1 class="py-5">8</h1></div>
                </li>
                <li class="list-inline-item" style="width: 300px;">
                    <div class="py-5 bg-dark"><h1 class="py-5">9</h1></div>
                </li>
            
            </ul>
        </div>
    </div>
    
    <div class="scroll-indicator" id="barWrapper">
        <div class="scroll-indicator-bar"  id="myBar"></div>
    </div>
    
    <div class="d-flex justify-content-between">
        <button>Prev</button>
        <button>Next</button>
    </div>
</div>

答案 2 :(得分:0)

是异步函数吗?

如果函数不是异步的(不需要像 api 那样响应) - 你不需要 useEffect。

import React from 'react';
import { Text, View } from 'react-native';
import {doCalculation} from '../util/helper'

const results = doCalculation();

const MyScreen = () => {

  return (
      <View> 
        {results.map(item=> <Text key={item.id}> {item.value} </Text>)}
      </View>
  )
}

export default MyScreen;
<块引用>

否则你应该等到结果来自服务器..

import React, { useState, useEffect } from 'react';
import { Text, View } from 'react-native';
import { doCalculation } from '../util/helper';

const MyScreen = () => {

  const [results, setResults] = useState(null) // or empty array

  useEffect(() => {
    (async () => {
      setResults(await doCalculation());
    })();
  }, []);

  return (
    <View>
      {results?.map(item => <Text key={item.id}> {item.value} </Text>) || "Loading..."}
    </View>
  )
}

export default MyScreen;

而且我可以使用更易读的代码:

  if (!results) {
    return <View>Loading...</View>
  }
  return (
    <View>
      {results.map(item => <Text key={item.id}> {item.value} </Text>)}
    </View>
  )

异步函数可以是这样的:

const doCalculation = () => {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve([{ id: 1, value: 1 }]);
    }, 2000);
  });
};

答案 3 :(得分:0)

下面是一个例子。根据上面的评论,您似乎希望在组件安装时调用它一次。您真正需要做的就是添加一个 useState

import {doCalculation} from '../util/helper'

const MyScreen = ({navigation}) => {
   const [calculatedData, setCalculatedData] = useState([])

   useEffect(() => {
     // I call a function from a helper module here. 
     // The result is a list of object.
     const result = doCalculation();
     setCalculatedData(result)

     // eslint-disable-next-line
  }, []);

  // renderer
  return (
      <View> 
        // Problem is 'result' is not accessible here, but I need to render it here
        {calculatedData.map(item=> <Text key={item.id}> {item.value} </Text>)}
      </View>
  )
}

export default MyScreen;
   const [calculatedData, setCalculatedData] = useState([])

useState 是一个用于存储变量状态的钩子。当在 setCalculatedData 中调用 useEffect 并使用空依赖数组时,它的行为类似于 componentDidMount() 并且仅在第一次挂载时运行。如果您将变量添加到依赖项数组,它将在每次其中一个时重新运行。改变。

您可以随时更改 calculatedData 中的数据,方法是调用 setCalculatedData 并将输入数据更改为。