【问题标题】:React functional component not updating on setState from parent component反应功能组件未从父组件更新 setState
【发布时间】:2022-01-16 22:29:13
【问题描述】:

我的 React 组件使用 apollo 通过 graphql 获取数据

class PopUpForm extends React.Component {

  constructor () {
    super()
    this.state = {
      shoptitle: "UpdateMe",
      popupbodyDesc: "UpdateMe"
    }
  }

render() 
{
    return (
        <>
        <Query query={STORE_META}>
          {({ data, loading, error, refetch }) => {
            
       
            if (loading) return <div>Loading…</div>;
            if (error) return <div>{error.message}</div>;
            if (!data) return (
              <p>Could not find metafields :(</p>
            );

            console.log(data);
             //loop over data
              var loopedmetafields = data.shop.metafields.edges
              console.log(loopedmetafields)
              loopedmetafields.forEach(element => {
                console.log(element.node.value)
                if (element.node.value === "ExtraShopDescription"){
                  
                  this.setState({
                    shoptitle: element.node.value
                  });
                  console.log(this.state.shoptitle)
                }
                if (element.node.value === "bodyDesc"){
                   
                  this.setState({
                    popupbodyDesc: element.node.value
                  });
                  console.log(this.state.popupbodyDesc)
                }
              });
            return (
              <>
                <AddTodo  mkey="ExtraShopDesc" namespace="ExtraShopDescription" desc={this.state.shoptitle} onUpdate={refetch} />
                <AddTodo  mkey="body" namespace="bodyDesc" desc={this.state.popupbodyDesc} onUpdate={refetch} />
              </>
            );
        }}
        </Query>
        </>
    )
    }
}

export default PopUpForm

令人沮丧的是,功能组件在查询设置状态之前呈现。理想情况下,功能组件只会在此之后呈现,因为我认为它已被烘焙到 apollo 库中,但似乎我错了,它似乎执行同步而不是异步

如你所见,我将 props 传递给子组件,在子组件中我使用这些来显示某人可能修改的当前值

功能组件在这里

 function AddTodo(props) {

let input;
const [desc, setDesc] = useState(props.desc);
//console.log(desc)

useEffect( () => {
  console.log('props updated');
  console.log(props)
}, [props.desc])

const [addTodo, { data, loading, error }] = useMutation(UPDATE_TEXT, {
    refetchQueries: [
        'STORE_META' // Query name
      ],
});

//console.log(data)
if (loading) return 'Submitting...';
if (error) return `Submission error! ${error.message}`;

return (
  <div>
    <form
      onSubmit={e => {
        console.log(input.value)
        setDesc(input.value)
        e.preventDefault();
        const newmetafields = {
            key: props.mkey,
            namespace: props.namespace,
            ownerId: "gid://shopify/Shop/55595073672",
            type: "single_line_text_field",
            value: input.value
        }
        addTodo({ variables: { metafields: newmetafields } });
        input.value = input.value
      }}
    >
        <p>This field denotes the title of your pop-up</p>
      <input className="titleInput" defaultValue={desc} 
        ref={node => {
          input = node;
        }}
      />
      <button className="buttonClick" type="submit">Update</button>
    </form>

  </div>
);

}

现在我需要在 PopUpForm 上调用 setState 时更新此组件

另一个堆栈溢出答案here给了我一些线索

将初始状态作为道具传递给组件是一种反模式 因为 getInitialState(在我们的例子中是构造函数)方法是 仅在组件第一次渲染时调用。再也不会了。意义 也就是说,如果您重新渲染该组件,将不同的值作为 prop,组件不会做出相应的反应,因为组件 将保持第一次呈现时的状态。这是很 容易出错。

因此我随后实现了 useEffect,但是 useEffect 中的 console.log 仍然是“updateMe”,而不是从 graphql 调用返回的值。

所以我在哪里

  • 我需要在 grapql 调用之后渲染功能组件 而且我已经操纵了数据,这似乎也是设计模式方面的最佳方法

  • 我需要 setState 来传递/渲染具有新值的功能组件

顺便说一句,如果我这样做

            <AddTodo  mkey="ExtraShopDesc" namespace="ExtraShopDescription" desc={data.shop.metafields.edges[0].node.value} onUpdate={refetch} /> 

它会起作用,但我不能总是期望值是 0 或 1,因为元字段可能已经定义了

【问题讨论】:

    标签: javascript reactjs react-hooks apollo


    【解决方案1】:

    我认为有比使用setState 更简单的方法来解决这个问题。例如,您可以像这样使用find

                  const shopTitleElement = loopedmetafields.find(element => {
                    return element.node.value === "ExtraShopDescription"
                  })
                  const shopBodyElement = loopedmetafields.find(element => {
                    return element.node.value === "bodyDesc"
                  });
                  return (
                  <>
                    <AddTodo  mkey="ExtraShopDesc" namespace="ExtraShopDescription" desc={shopTitleElement.node.value} onUpdate={refetch} />
                    <AddTodo  mkey="body" namespace="bodyDesc" desc={shopBodyElement.node.value} onUpdate={refetch} />
                  </>
                );
    

    【讨论】:

      猜你喜欢
      • 2020-12-28
      • 1970-01-01
      • 2022-11-22
      • 2019-12-04
      • 1970-01-01
      • 2017-04-17
      • 1970-01-01
      • 2020-09-01
      • 2022-01-07
      相关资源
      最近更新 更多