Javascript 函数内部的状态始终相同/初始

Javascript 函数内部的状态始终相同/初始,javascript,reactjs,react-hooks,javascript-objects,Javascript,Reactjs,React Hooks,Javascript Objects,从对象调用remove()函数。如何在remove()函数中获取更新的状态值 const [InfoBoxPin, setInfoBoxPin] = useState([]) const createInfoBoxPin = (descriptions) =>{ var newPin = { "location":currentLoc, "addHand

从对象调用remove()函数。如何在remove()函数中获取更新的状态值

const [InfoBoxPin, setInfoBoxPin] = useState([]) 

const createInfoBoxPin = (descriptions) =>{
       
           var newPin = {
                "location":currentLoc, 
                "addHandler":"mouseover", 
                "infoboxOption": { 
                title: 'Comment', 
                description: "No comment Added",
                actions: [{
                    label:'Remove Pin',
                    eventHandler: function () {
                        remove(newPin.location) //FUNCTION CALLED HERE
                    }
                }] }
                
                }
            setInfoBoxPin((InfoBoxPin)=>[...InfoBoxPin, newPin ]) // UPDATE STATE. Push the above object.
       
    }

const remove = (pos) =>{    
        console.log(InfoBoxPin)    //NEVER GETTING UPDATED STATE HERE.

        //Other codes here......
    }

这是bing地图信息卡。Eventhandler创建了一个可以调用任何函数的按钮。

问题在于,您在
删除
函数中引用了旧的状态信息

const [InfoBoxPin, setInfoBoxPin] = useState([]) 

const createInfoBoxPin = (descriptions) =>{
       
           var newPin = {
                "location":currentLoc, 
                "addHandler":"mouseover", 
                "infoboxOption": { 
                title: 'Comment', 
                description: "No comment Added",
                actions: [{
                    label:'Remove Pin',
                    eventHandler: function () {
                        remove(newPin.location) //FUNCTION CALLED HERE
                    }
                }] }
                
                }
            setInfoBoxPin((InfoBoxPin)=>[...InfoBoxPin, newPin ]) // UPDATE STATE. Push the above object.
       
    }

const remove = (pos) =>{    
        console.log(InfoBoxPin)    //NEVER GETTING UPDATED STATE HERE.

        //Other codes here......
    }
当您调用
setInfoBoxPin
时,
InfoBoxPin
的状态将注册,以便在下次呈现UI时进行更新。这意味着在当前状态下,它将是相同的(空),并且指向它的所有链接都将引用空数组

为了解决这个问题,您必须将新状态从视图本身传递给相应的函数

示例#1 在这里,我为您创建了一个CodeSandBox:

下面是从中截取的代码:

import React, { useState } from "react";
import "./styles.css";

export default function App() {
  const [state, setState] = useState({
    InfoBoxPin: [],
    output: []
  });

  const createInfoBoxPin = (descriptions) => {
    var newPin = {
      location: Math.round(Math.random(10) * 1000),
      addHandler: "mouseover",
      infoboxOption: {
        title: "Comment",
        description: "No comment Added",
        actions: [
          {
            label: "Remove Pin",
            eventHandler: removePin
          },
          {
            label: "Update Pin",
            eventHandler: updatePin
          }
        ]
      }
    };
    setState({ ...state, InfoBoxPin: [...state.InfoBoxPin, newPin] });
  };

  const updatePin = (key, state) => {
    var text = `Updating pin with key #${key} - ${state.InfoBoxPin[key].location}`;

    setState({ ...state, output: [...state.output, text] });

    console.log(text, state.InfoBoxPin);
  };

  const removePin = (key, state) => {
    var text = `Removing pin with key #${key} - ${state.InfoBoxPin[key].location}`;

    setState({ ...state, output: [...state.output, text] });

    console.log(text, state.InfoBoxPin);
  };

  return (
    <div className="App">
      <h1>React setState Example</h1>
      <h2>Click on a button to add new Pin</h2>
      <button onClick={createInfoBoxPin}>Add new Pin</button>
      <div>----</div>
      {state.InfoBoxPin.map((pin, pin_key) => {
        return (
          <div key={pin_key}>
            <span>Pin: {pin.location} &nbsp;</span>
            {pin.infoboxOption.actions.map((action, action_key) => {
              return (
                <button
                  key={action_key}
                  onClick={() => action.eventHandler(pin_key, state)}
                >
                  {action.label}
                </button>
              );
            })}
          </div>
        );
      })}
      <h4> OUTPUT </h4>
      <ul style={{ textAlign: "left" }}>
        {state.output.map((txt, i) => {
          return <li key={i}>{txt}</li>;
        })}
      </ul>
    </div>
  );
}
示例#3(ES6)未访问创建的元素 这个例子将展示如何使用我们自己的参数和来自自动生成HTML元素事件的状态数据处理来自第三方库的回调

代码沙盒链接:

代码段:

import React from "react";
import "./styles.css";

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      InfoBoxPin: [],
      pinName: ""
    };

    /* ------------ method #1 using .bind(this) ------------ */
    this.setPinName = this.setPinName.bind(this);
  }

  remove(key) {
    this.state.InfoBoxPin.splice(key, 1);
    this.setState({ InfoBoxPin: this.state.InfoBoxPin });
  }

  add(pinName) {
    this.state.InfoBoxPin.push(pinName);
    this.setState({ InfoBoxPin: this.state.InfoBoxPin });
  }

  processPinNameAndAdd() {
    let pinName = this.state.pinName.trim();

    if (pinName === "") pinName = Math.round(Math.random() * 1000);

    this.add(pinName);
  }

  setPinName(event) {
    this.setState({ pinName: event.target.value });
  }

  render() {
    return (
      <div className="shopping-list">
        <h1>Pin List</h1>
        <p>Hit "Add New Pin" button.</p>
        <p>(Optional) Provide your own name for the pin</p>

        <input
          onInput={this.setPinName}
          value={this.state.pinName}
          placeholder="Custom name"
        ></input>

        {/* ------------ method #2 using .call(this) ------------ */}
        <button onClick={() => this.processPinNameAndAdd.call(this)}>
          Add new Pin
        </button>

        <ul>
          {this.state.InfoBoxPin.map((pin, pinKey) => {
            return (
              <li key={pinKey}>
                <div>pin: {pin}</div>

                {/* ------------ method #3 using .apply(this, [args]) ------------ */}
                <button onClick={() => this.remove.apply(this, [pinKey])}>
                  Delete Pin
                </button>
              </li>
            );
          })}
        </ul>
      </div>
    );
  }
}

export default App;
import React from "react";
import "./styles.css";

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      InfoBoxPin: [],
      lastPinId: 0,
      pinName: ""
    };

    this.setPinName = this.setPinName.bind(this);
  }

  remove(id) {
    let keyToRemove = null;

    this.state.InfoBoxPin.forEach((pin, key) => {
      if (pin.id === id) keyToRemove = key;
    });

    this.state.InfoBoxPin.splice(keyToRemove, 1);
    this.setState({ InfoBoxPin: this.state.InfoBoxPin });
  }

  add(data, id) {
    this.state.InfoBoxPin.push({ id: id, data: data });
    this.setState({
      InfoBoxPin: this.state.InfoBoxPin,
      lastPinId: id
    });
  }

  processPinNameAndAdd() {
    let pinName = this.state.pinName.trim();

    if (pinName === "") pinName = Math.round(Math.random() * 1000);

    var newPinId = this.state.lastPinId + 1;

    var newPin = {
      location: pinName,
      addHandler: "mouseover",
      infoboxOption: {
        title: "Comment",
        description: "No comment Added",
        actions: [
          {
            label: "Remove Pin #" + newPinId,
            // [ES6 class only] using () => func() for callback function
            // By doing so we don't need to use bind,call,apply to pass class ref [this] to a function.
            eventHandler: () => this.remove(newPinId)
          }
        ]
      }
    };

    this.add(newPin, newPinId);
  }

  setPinName(event) {
    this.setState({ pinName: event.target.value });
  }

  render() {
    return (
      <div className="shopping-list">
        <h1>Pin List</h1>
        <p>Hit "Add New Pin" button.</p>
        <p>(Optional) Provide your own name for the pin</p>

        <input onInput={this.setPinName} value={this.state.pinName}></input>

        {/* 
          [ES6 class only] Using {() => func()} for event handler.
          By doing so we don't need to use func.bind(this) for passing class ref at constructor 
        */}
        <button onClick={() => this.processPinNameAndAdd()}>Add new Pin</button>

        <ul>
          {this.state.InfoBoxPin.map((pin, pKey) => {
            return (
              <li key={pKey}>
                <div>pin: {pin.data.location}</div>

                {pin.data.infoboxOption.actions.map((action, aKey) => {
                  return (
                    <button key={aKey} onClick={action.eventHandler}>
                      {action.label}
                    </button>
                  );
                })}
              </li>
            );
          })}
        </ul>
      </div>
    );
  }
}

export default App;


请注意,使用arrow函数
()=>func
将类ref传递给
remove
函数非常重要。

感谢您的努力,但您不能更改newPin对象的结构,因为Bing map将以这种格式接收它。事件处理程序键在Bing地图上生成一个可单击的按钮。因此,您必须维护它们提供的结构,eventHandler:function(){}。我们必须为事件处理程序分配一个函数。我们不能在那里打字。有什么想法吗?我已经更新了我的答案和代码沙盒示例。你可以去看看。希望这将对您有所帮助。添加了另一个使用类的示例。这创造了一个机会,可以使用一些不同的方法来检索应用程序状态。非常感谢。我会尝试你的方法。我尝试了你的方法,但我的“关键”是获取指针事件。你遇到了JavaScript中称为“陈旧闭包”的问题,它不是特定的反应,但在引用状态时很容易在react中命中。。。
const [InfoBoxPin, setInfoBoxPin] = useState([]) 

const createInfoBoxPin = (descriptions) =>{
       
           var newPin = {
                "location":currentLoc, 
                "addHandler":"mouseover", 
                "infoboxOption": { 
                title: 'Comment', 
                description: "No comment Added",
                actions: [{
                    label:'Remove Pin',
                    eventHandler: function () {
                        remove(newPin.location) //FUNCTION CALLED HERE
                    }
                }] }
                
                }
            setInfoBoxPin((InfoBoxPin)=>[...InfoBoxPin, newPin ]) // UPDATE STATE. Push the above object.
       
    }

const remove = (pos) =>{    
        console.log(InfoBoxPin)    //NEVER GETTING UPDATED STATE HERE.

        //Other codes here......
    }