如何将数据从原生JavaScript传递到React函数组件

4
我正在尝试从“常规”(原生)JavaScript中更新(setState)React函数组件。
我在StackOverflow上搜索过,但所有答案都涉及从React传递数据到(原生)JavaScript,而不是相反。
让我们以docs中的示例为例。
import React, { useState } from 'react';

function Example() {
  // Declare a new state variable, which we'll call "count"
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

要在JavaScript中渲染它,我这样做:

let example = ReactDOM.render(
    <Example />,
    document.getElementById('example-wrapper')
);

现在假设我想要在React之外的普通JavaScript代码中手动更新计数。例如:
function updateExampleCount(newCount) {
    example.setCount(newCount);   // ???
}

由于setCount是函数内的私有变量,而render返回的example为null,因此无法访问组件状态。

如果使用类组件,则 render 将返回对组件的引用,然后可以调用 example.setState 。但是如果可以避免,我更喜欢不将组件转换为类。

render 的文档 say

在提供的容器中将 React 元素呈现到 DOM 中,并返回对组件的引用(或对于无状态组件返回 null)。

但是,我的组件确实具有状态(count),只是它没有被识别。 如果无法使用 render 返回的值,是否还有其他方法来“获取”组件,然后使用 setCount(或其他设置状态的方法)?

还是我必须使用类组件?

谢谢。


2
我认为这是一种特性而不是错误。组件应该自己负责其状态,其状态只能从内部更改,使代码更易于理解和推理。如果您想从外部设置计数,请将其作为属性传递。 - Bergi
你想在哪里以及如何调用 updateExampleCount 函数?每页要渲染多少个 Example,只有一个吗? - Bergi
3个回答

2

无法从组件外部访问状态。这就像尝试从函数外部访问本地作用域变量一样。

即使使用类组件也没有帮助,因为您将无法获取在React应用程序内创建的类实例。


如果您想从应用程序外部触发状态更改,则应用程序需要提供事件处理程序。

例如(非常快速和简单的):

const outside = {
    value: 2,
    callbacks: [],
    addCallback: function (callback) { this.callbacks.push(callback); },
    setValue: function (value) { 
        this.value = value; 
        this.callbacks.forEach(
            callback => callback(this.value)
        );
    }
};

function Component = () => {
    const [val, setVal] = useState(outside.value);
    useEffect(() => {
        outside.addCallback((value) => setVal(value));
    }, []);
    return <p>{val}</p>
}

2
可以实现。您可以将您的setCount函数作为参数传递,以便在 React 之外的 JS 中使用它 - 但我不会真正建议这样做。
我建议您将业务逻辑和 React 逻辑分开。
唯一需要了解状态并将使用它的是 React 组件本身。我会以一种不与 React 耦合且不必以任何方式使用或依赖于 React 状态的方式构建您的代码。
这在开始时说起来比做起来容易。如果您需要帮助,请提供您尝试以这种方式解决的用例,可能会提供更好的答案。

使用场景是用于显示和编辑标签。我有一个页面,代表一些物品,比如说假日礼物,用户可以购买,并且用户可以为该物品添加标签,例如“酷炫礼物”,“假日”,“好主意”等等。整个代码已经存在并且是用纯JavaScript编写的。我想慢慢将其转换为React。我创建了一个React组件,仅用于显示标签,它的“状态”是要显示的标签列表。但是在纯JS中,_编辑_标签是在完全不同的地方完成的。我想执行component.setState({tags: newTags})(在纯JS中),但我不能这样做。 - Arnon Yaari

0

可以通过扩展Example,使其将对setCount函数的引用传递回父代码来完成,如下所示。(如果这与Oli提到的相同,则我在回答之前已经有了相同的想法并实现了一个可行的实现)

const { useState } = React;

// functionFromComponent will store the function from Example.
let functionFromComponent = undefined;
const setter = (someFn) => functionFromComponent = someFn;

const Example = ({ setFunction }) => { // take `setFunction` from props
  const [count, setCount] = useState(0);

  setFunction(setCount); // pass setCount to the parent code
  
  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

ReactDOM.render(
    <Example setFunction={setter} />,
    document.getElementById('example-wrapper')
);

function buttonClicked() {
  if (functionFromComponent) {
    functionFromComponent(777);
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>

<div id="example-wrapper"></div>

<button id="regularButton" onclick="buttonClicked()">Regular button</button>


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接