在React中,管理动态添加按钮的按钮值状态。

huangapple go评论69阅读模式
英文:

In React manage button value state for dynamically added buttons

问题

以下是代码的中文翻译部分:

const { useState } = React;

const Chat = () => {
    const [myMessages, setMyMessages] = useState([]);
    const [message, setMessage] = useState("");
    const [myButtons, setMyButtons] = useState([{}]);

    const addNewMessage = () => {

        let buttonIndex = myMessages.length;
        setMyButtons(myButtons => [...myButtons, { value: "复制消息" }]);

        let newMessage = (
            <div>
                <div>{message}</div>
                <button className="copy-to-clipboard-button" onClick={() => { copyToClipboard(buttonIndex, message); }}>
                    {myButtons[buttonIndex].value}
                </button>
            </div>
        );

        setMyMessages([...myMessages, newMessage]);

    };

    const copyToClipboard = (i, text) => {
        alert("已复制");
        navigator.clipboard.writeText(text);
        let allButtons = myButtons.slice();
        allButtons[i].value = "已复制!";
        setMyButtons([...allButtons]);
    };

    const handleChange = (event) => {
        setMessage(event.target.value);
    };

    return (
        <div>
            <div style={{ maxHeight: "80vh", minHeight: "90vh", maxWidth: "96vw" }}>
                {myMessages.map(message => <div>{message}</div>)}
                <input
                    type="text"
                    id="message"
                    name="message"
                    onChange={handleChange}
                    value={message}
                />
                <button onClick={addNewMessage}>发送</button>
            </div>
        </div>
    )
};

ReactDOM.createRoot(document.body).render(<Chat />);

请注意,我已将按钮文本从"Copy message"和"Copied!"翻译为中文。如果您需要更多帮助或有其他问题,请随时提问。

英文:

The code below is a small, very simplified snippet from a React messaging app

<!-- begin snippet: js hide: false console: true babel: true -->

<!-- language: lang-js -->

const { useState } = React;
const Chat = () =&gt; {
const [myMessages, setMyMessages] = useState([]);
const [message, setMessage] = useState(&quot;&quot;);
const [myButtons, setMyButtons] = useState([{}]);
const addNewMessage = () =&gt; {
let buttonIndex = myMessages.length;
setMyButtons(myButtons =&gt; [...myButtons, { value: &quot;Copy message&quot; }]);
let newMessage =
(&lt;div&gt;
&lt;div&gt;{message}&lt;/div&gt;
&lt;button className=&quot;copy-to-clipboard-button&quot; onClick={() =&gt; { copyToClipboard(buttonIndex, message); }}&gt;
{myButtons[buttonIndex].value}
&lt;/button&gt;
&lt;/div&gt;);
setMyMessages([...myMessages, newMessage]);
};
const copyToClipboard = (i, text) =&gt; {
alert(&quot;copied&quot;);
navigator.clipboard.writeText(text);
let allButtons = myButtons.slice();
allButtons[i].value = &quot;Copied!&quot;;
setMyButtons([...allButtons]);
};
const handleChange = (event) =&gt; {
setMessage(event.target.value);
};
return (
&lt;div&gt;
&lt;div style={{ maxHeight: &quot;80vh&quot;, minHeight: &quot;90vh&quot;, maxWidth: &quot;96vw&quot; }}&gt;
&lt;div&gt;{myMessages.map(message =&gt; &lt;div&gt;{message}&lt;/div&gt;)}
&lt;input
type=&quot;text&quot;
id=&quot;message&quot;
name=&quot;message&quot;
onChange={handleChange}
value={message}
/&gt;
&lt;button onClick={addNewMessage}&gt;Go!&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
)
};
ReactDOM.createRoot(document.body).render(&lt;Chat /&gt;);

<!-- language: lang-html -->

&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js&quot;&gt;&lt;/script&gt;

<!-- end snippet -->

This code is for demonstration purposes only in order to spotlight the problem I'm trying to solve. Basically, when a new message is added, a copy to clipboard button is added with it. The value of each these dynamically added buttons is set to {myButtons[buttonIndex].value} with the intention that I'm tying the button's value to a state variable that can be updated and rendered. This value is set correctly when the component is first added.

When a 'copy-to-clipboard-button' is clicked, the copyToClipboard method is called and the copy functionality works correctly. The next step is to change the button value to "Copied!". Although the array is updated correctly, the value of the button is not updated. I suspect that the problem is that when the button is created, it sets the value as a static value and is not tied to that state variable going forward. My thinking is that there is a way to indicate that the button value should be tied to state ongoing, but I'm not able to find the right syntax. Perhaps there's a better way to approach this altogether. Looking for some guidance. Thanks!

答案1

得分: 1

以下是代码部分的翻译:

const { useState } = React;

const Message = ({ message, buttonIndex }) => {
  const [buttonValue, setButtonValue] = useState("复制消息");

  const copyToClipboard = (text) => {
    alert("已复制");
    navigator.clipboard.writeText(text);
    setButtonValue("已复制!");
  };

  return (
    <div>
      <div>{message}</div>
      <button
        className="复制到剪贴板按钮"
        onClick={() => {
          copyToClipboard(message);
        }}
      >
        {buttonValue}
      </button>
    </div>
  );
};

const Chat = () => {
  const [myMessages, setMyMessages] = useState([]);
  const [message, setMessage] = useState("");

  const addNewMessage = () => {
    setMyMessages([...myMessages, message]);
  };

  const handleChange = (event) => {
    setMessage(event.target.value);
  };

  return (
    <div>
      <div style={{ maxHeight: "80vh", minHeight: "90vh", maxWidth: "96vw" }}>
        {myMessages.map((message, index) => (
          <Message key={index} message={message} buttonIndex={index} />
        ))}
        <input type="text" id="message" name="message" onChange={handleChange} value={message} />
        <button onClick={addNewMessage}>发送</button>
      </div>
    </div>
  );
};

ReactDOM.createRoot(document.body).render(<Chat />);

希望这有所帮助。

英文:

<!-- begin snippet: js hide: false console: true babel: true -->

<!-- language: lang-js -->

const { useState } = React;
const Message = ({ message, buttonIndex }) =&gt; {
const [buttonValue, setButtonValue] = useState(&quot;Copy message&quot;);
const copyToClipboard = (text) =&gt; {
alert(&quot;copied&quot;);
navigator.clipboard.writeText(text);
setButtonValue(&quot;Copied!&quot;);
};
return (
&lt;div&gt;
&lt;div&gt;{message}&lt;/div&gt;
&lt;button
className=&quot;copy-to-clipboard-button&quot;
onClick={() =&gt; {
copyToClipboard(message);
}}
&gt;
{buttonValue}
&lt;/button&gt;
&lt;/div&gt;
);
};
const Chat = () =&gt; {
const [myMessages, setMyMessages] = useState([]);
const [message, setMessage] = useState(&quot;&quot;);
const addNewMessage = () =&gt; {
setMyMessages([...myMessages, message]);
};
const handleChange = (event) =&gt; {
setMessage(event.target.value);
};
return (
&lt;div&gt;
&lt;div style={{ maxHeight: &quot;80vh&quot;, minHeight: &quot;90vh&quot;, maxWidth: &quot;96vw&quot; }}&gt;
{myMessages.map((message, index) =&gt; (
&lt;Message key={index} message={message} buttonIndex={index} /&gt;
))}
&lt;input type=&quot;text&quot; id=&quot;message&quot; name=&quot;message&quot; onChange={handleChange} value={message} /&gt;
&lt;button onClick={addNewMessage}&gt;Go!&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
);
};
ReactDOM.createRoot(document.body).render(&lt;Chat /&gt;);

<!-- language: lang-html -->

&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js&quot;&gt;&lt;/script&gt;

<!-- end snippet -->

if i got your mean correct , create a separate component for each message and its associated button. This way, each button's value would be tied to its own state variable and can be updated independently

答案2

得分: 1

以下是翻译好的部分:

你需要一个触发引用的函数:

如果你使用以下代码片段:

let newMessage =
    (<div>
        <div>{message}</div>
        <button className="copy-to-clipboard-button" onClick={() => { copyToClipboard(buttonIndex, message); }}>
            {myButtons[buttonIndex].value}
        </button>
    </div>);

编译后的代码如下:

let newMessage = createElement('div', [
    createElement('div', message),
    createElement('button', {...}, [myButtons[buttonIndex].value])
])

这会导致在创建时进行静态编译,而不是使用函数。建议改成以下方式:

let newMessage =
    () => {
    // 作用域内的值
    let msg = message
    return (<div>
        <div>{msg}</div>
        <button className="copy-to-clipboard-button" onClick={() => { copyToClipboard(buttonIndex, msg); }}>
            {myButtons[buttonIndex].value}
        </button>
    </div>);
}

希望这对你有所帮助。

英文:

You need a function to trigger references:

If you use

  let newMessage =
            (&lt;div&gt;
                &lt;div&gt;{message}&lt;/div&gt;
                &lt;button className=&quot;copy-to-clipboard-button&quot; onClick={() =&gt; { copyToClipboard(buttonIndex, message); }}&gt;
                    {myButtons[buttonIndex].value}
                &lt;/button&gt;
            &lt;/div&gt;);

after compile:

  let newMessage = createElement(&#39;div&#39;, [
    createElement(&#39;div&#39;, message),
    createElement(&#39;button&#39;, {...}, [myButtons[buttonIndex].value])
  ])

this leads to static compilation at creation time instead use function

 let newMessage =
            () =&gt; {
            // scope value
            let msg = message
            return (&lt;div&gt;
                &lt;div&gt;{msg}&lt;/div&gt;
                &lt;button className=&quot;copy-to-clipboard-button&quot; onClick={() =&gt; { copyToClipboard(buttonIndex, msg); }}&gt;
                    {myButtons[buttonIndex].value}
                &lt;/button&gt;
            &lt;/div&gt;);
        }

<!-- begin snippet: js hide: false console: true babel: true -->

<!-- language: lang-js -->

const { useState } = React;
const Chat = () =&gt; {
const [myMessages, setMyMessages] = useState([]);
const [message, setMessage] = useState(&quot;&quot;);
const [myButtons, setMyButtons] = useState([{}]);
const addNewMessage = () =&gt; {
let buttonIndex = myButtons.length;
const currentButton = { value: &quot;Copy message&quot; }
myButtons.push(currentButton)
setMyButtons([...myButtons])
// you need a function to trigger references
let newMessage =
(myButtons) =&gt; {
// scope value
let msg = message
return (&lt;div&gt;
&lt;div&gt;{msg}&lt;/div&gt;
&lt;button className=&quot;copy-to-clipboard-button&quot; onClick={() =&gt; { copyToClipboard(currentButton, msg); }}&gt;
{currentButton.value}
&lt;/button&gt;
&lt;/div&gt;);
}
setMyMessages([...myMessages, newMessage]);
};
const copyToClipboard = (currentButton, text) =&gt; {
alert(&quot;copied &quot;+ text);
navigator.clipboard.writeText(text)
currentButton.value = &quot;Copied!&quot;;
setMyButtons([...myButtons]);
};
const handleChange = (event) =&gt; {
setMessage(event.target.value);
};
return (
&lt;div&gt;
&lt;div style={{ maxHeight: &quot;80vh&quot;, minHeight: &quot;90vh&quot;, maxWidth: &quot;96vw&quot; }}&gt;
&lt;div&gt;{myMessages.map(message =&gt; &lt;div&gt;{message(myButtons)}&lt;/div&gt;)}
&lt;input
type=&quot;text&quot;
id=&quot;message&quot;
name=&quot;message&quot;
onChange={handleChange}
value={message}
/&gt;
&lt;button onClick={addNewMessage}&gt;Go!&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
)
};
ReactDOM.createRoot(document.body).render(&lt;Chat /&gt;);

<!-- language: lang-html -->

&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js&quot;&gt;&lt;/script&gt;

<!-- end snippet -->

> I fixed some bugs in your code or use diff to see details

huangapple
  • 本文由 发表于 2023年6月9日 07:19:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/76436276.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定