繁体   English   中英

反应功能组件未从父组件更新 setState

[英]React functional component not updating on setState from parent component

我的 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

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

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

功能组件在这里

 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 时更新此组件

这里的另一个堆栈溢出答案给了我一些线索

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

因此,为什么我随后实现了 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,因为元字段可能已经定义了

我认为有一种比使用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} />
              </>
            );

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM