【问题标题】:How do I pass a value from a promise to a component prop in react native?如何在 react native 中将值从 promise 传递给组件 prop?
【发布时间】:2019-11-08 08:35:14
【问题描述】:

编辑:我不明白投反对票的原因,这是一个很好的问题,本网站上没有其他问题解决了我的问题。我只是预先加载了数据来解决我的问题,但如果不使用功能组件,这仍然无法解决问题。

我正在尝试将用户最后一条消息传递给 ListItem 字幕道具,但我似乎无法找到从 promise/then 调用返回值的方法。它返回一个承诺,而不是返回一个“失败的道具类型”的值。我考虑过使用状态,但后来我认为我不能再调用 ListItem 组件中的函数了。

  getMsg = id => {
    const m = fireStoreDB
      .getUserLastMessage(fireStoreDB.getUID, id)
      .then(msg => {
        return msg;
      });
    return m;
  };

  renderItem = ({ item }) => (
    <ListItem
      onPress={() => {
        this.props.navigation.navigate('Chat', {
          userTo: item.id,
          UserToUsername: item.username
        });
      }}
      title={item.username}
      subtitle={this.getMsg(item.id)} // failed prop type
      bottomDivider
      chevron
    />
  );

【问题讨论】:

  • @HMR - 我认为它比这更具体一些。
  • 您可以在解析中使用setState
  • The following answer 接近你能做的,如果你不能使用功能组件,那么我发布的链接会给你一个如何用类组件解决这个问题的想法(只检查代码, babel 不需要配置)
  • @HMR 没有,但我确实解决了这个问题。

标签: javascript reactjs react-native react-native-flatlist react-native-elements


【解决方案1】:

如果ListItem 期望看到它的subtitle 属性的承诺,你只能这样做,我猜它不会。 ;-)(猜测是因为我还没有玩过 React Native。React,但不是 React Native。)

相反,组件需要有两种状态:

  • 字幕尚未加载
  • 字幕已加载

...并渲染这些状态中的每一个。如果您不希望组件具有状态,那么您需要在父组件中处理异步查询,并且只有在您拥有所需信息时才呈现 this 组件。

【讨论】:

  • 我最终找到了一种方法来获取 componentDidMount 中的所有信息,这样我就可以一次将它们传递给ListItem
  • @CLUTCHER - 这是经典方法之一,不错!
【解决方案2】:

如果“最后一条消息”是特定于 ListItem 组件的内容,而不是您手头的内容,您可能希望让列表项自行发出网络请求。我会将函数移到ListItem 中。您需要设置一些状态来保存该值,并可能进行一些条件渲染。然后,您需要在安装组件时调用此函数。我假设您正在使用功能组件,所以useEffect() 应该在这里帮助您:

//put this is a library of custom hooks you may want to use
//  this in other places
const useIsMounted = () => {
  const isMounted = useRef(false);
  useEffect(() => {
    isMounted.current = true;
    return () => (isMounted.current = false);
  }, []);
  return isMounted;
};

const ListItem = ({
  title,
  bottomDivider,
  chevron,
  onPress,
  id, //hae to pass id to ListItem
}) => {
  const [lastMessage, setLastMessage] = useState(null);
  const isMounted = useIsMounted();
  React.useEffect(() => {
    async function get() {
      const m = await fireStoreDB.getUserLastMessage(
        fireStoreDB.getUID,
        id
      );
      //before setting state check if component is still mounted
      if (isMounted.current) {
        setLastMessage(m);
      }
    }
    get();
  }, [id, isMounted]);

  return lastMessage ? <Text>DO SOMETHING</Text> : null;
};

【讨论】:

  • 你忘记了 async: useEffect(async () =&gt; { 但你也可以这样做 fireStoreDB.get().then(setLastMessage) 并忽略 async 并等待。
  • 哎呀,你是对的。尽管如此,虽然它只是语法糖,但当您快速扫描代码时,它是一个很好的视觉标记,并且更具可读性。
  • 您的答案很接近,但应在设置状态之前检查组件是否为still mounted。效果缺少依赖项(id)并且效果不应该是异步函数(linter 会抱怨)。如果你愿意,我可以调整你的答案。
  • 好的,我在手机自动取款机上
  • 我更新了你的答案,没有错误处理或加载消息,但接近了。
【解决方案3】:

我通过在 componentDidMount 上的另一个 promise 方法中使用该 promise 方法解决了这个问题,并将用户的最后一条消息添加为所有用户的额外字段。这样我就可以让所有用户信息处于一种状态以填充 ListItem。

  componentDidMount() {
    fireStoreDB
      .getAllUsersExceptCurrent()
      .then(users =>
        Promise.all(
          users.map(({ id, username }) =>
            fireStoreDB
              .getUserLastMessage(fireStoreDB.getUID, id)
              .then(message => ({ id, username, message }))
          )
        )
      )
      .then(usersInfo => {
        this.setState({ usersInfo });
      });
  }

  renderItem = ({ item }) => (
    <ListItem
      onPress={() => {
        this.props.navigation.navigate('Chat', {
          userTo: item.id,
          UserToUsername: item.username
        });
      }}
      title={item.username}
      subtitle={item.message}
      bottomDivider
      chevron
    />
  );

【讨论】:

  • 你正在改变一个值并设置状态,假设 getUserLastMessage 将以与请求相同的顺序解析(或列表中用户的顺序不重要)并且不必要地设置状态多次.使用 Promise.all,您可以设置一次状态,以正确的顺序获取响应,而无需更改临时值。
  • @HMR 我将来自getAllUsersExceptCurrent 的值用于getUserLastMessage,因此我无法将它们都包装在Promise.all 中。但是,我确实通过使用普通的 for 循环修复了“多次设置状态”,并检查了它何时是最后一个设置状态的项目。
  • CLUTCHER,@HMR 是正确的,问题中的版本可能不可靠(如果您对消息的最后一个请求在前一个请求之前完成,则您过早设置状态)。以下是使用Promise.all 的方法:pastebin.com/VmMqs9i2
  • 这是内联代码,但 cmets 中的代码很难看。 :-) componentDidMount() { // Get the users fireStoreDB.getAllUsersExceptCurrent() .then( // Map them to objects including last message users =&gt; Promise.all(users.map( // Uses destructuring on the user to pick out `id` and `username` ({id, username}) =&gt; fireStoreDB .getUserLastMessage(fireStoreDB.getUID, user.id) // Builds and returns object from `id`, `username`, and `message` .then(message =&gt; ({id, username, message})) ) ) ) .then(usersInfo =&gt; {
  • // Now that we have all the `usersInfo` entries, set state this.setState({usersInfo}); }); }
猜你喜欢
  • 2019-12-06
  • 2018-12-28
  • 2019-01-18
  • 1970-01-01
  • 2018-01-15
  • 2018-04-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多