反应功能组件未从父组件更新 setState
Posted
技术标签:
【中文标题】反应功能组件未从父组件更新 setState【英文标题】:React functional component not updating on setState from parent component 【发布时间】: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,因为元字段可能已经定义了
【问题讨论】:
【参考方案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 />
</>
);
【讨论】:
以上是关于反应功能组件未从父组件更新 setState的主要内容,如果未能解决你的问题,请参考以下文章