簡體   English   中英

React組件未使用地圖功能渲染

[英]React component not getting rendered with map function

調用loadAll()時,不會渲染我的LinkItem組件。 僅在調用handleClick()或handleChange()之后才呈現它。

import React, { Component } from "react";
var Datastore = require("nedb");
var db = new Datastore({ filename: __dirname + "/userdata" });
db.loadDatabase(function(err) {

});

function LinkItem(props) {
  console.log("Rendered");
  return (
    <div>
      <a href={props.name}>{props.name}</a>
    </div>
  );
}

export default class List extends Component {
  constructor(props) {
    super(props);
    this.state = {
      link: "",
      data: [],
    };
    this.handleClick = this.handleClick.bind(this);
    this.handleChange = this.handleChange.bind(this);
    this.loadAll = this.loadAll.bind(this);
  }

  loadAll() {
    let loadData = [];
    db.find({ type: "link" }, function(err, docs) {
      docs.map(doc => loadData.push(doc.name));
    });
    this.setState({ data: loadData });
  }

  // add new item to data set
  handleClick() {
    this.setState({
      data: [...this.state.data, this.state.link]
    });
    const doc = { name: this.state.link, type: "link" };
    db.insert(doc, (err, docs) => {
      console.log("Inserted");
      console.log(docs);
    });
  }

  // handles form input changes
  handleChange(event) {
    this.setState({ link: event.target.value });
  }

在渲染功能中,我使用地圖來渲染每個LinkItem組件。 但是,當我在LinkItem組件上檢查console.log時,根本不會創建它們。 它們僅在handleClick和調用handleChange時出現。

  render() {
    const data = this.state.data;

      return (
        <div>
          <button onClick={this.loadAll}>Load data</button>
          <input
            type="text"
            value={this.state.link}
            onChange={this.handleChange}
          />
          <button onClick={this.handleClick}>Add</button>
          {console.log(data)}
          {/* render each data */}
          {data.map((item, index) => (
            <LinkItem name={item} key={index} />
          ))}
        </div>
      );
    }

}

基本上,我想發生的是調用loadData時,所有數據都在LinkItem組件中呈現。

注意:這不是重復項。 我檢查了stackoverflow中的其他問題,這些問題在map函數中沒有返回。 對我來說不是這樣。 僅當其他狀態值更改時,它才最終呈現。

編輯:我能夠通過將setState放在db find中並將回調更改為箭頭函數來修復它。 對於使用nedb進行響應的您可能會有所幫助。

  loadAll() {
    db.find({ type: "link" }, (err, docs) => { // changed to arrow function
      this.setState({ data: docs.map(doc => doc.name)});
    });
  } 

您的db.find函數是異步的,您的程序將繼續運行,而不必等待它完成:

  loadAll() {
    let loadData = [];
    db.find({ type: "link" }, function(err, docs) {
      docs.map(doc => loadData.push(doc.name));
    });
    this.setState({ data: loadData });
  }

您有2個解決方案來修復它。

setState放入回調中:

  loadAll() {
    let loadData = [];
    db.find({ type: "link" }, function(err, docs) {
      docs.map(doc => loadData.push(doc.name));
      this.setState({ data: loadData });
    });
  }

或等待您的來電:

  loadAll = async() => {
    let loadData = [];
    const docs = await db.find({ type: "link" });
    docs.map(doc => loadData.push(doc.name));
    this.setState({ data: loadData });
  }

同樣,map函數將返回一個包含您的值的新數組。 以下語法較短,並且具有相同的作用:

loadAll = async () => {
    this.setState({ 
        data: (await db.find({ type: "link" })).map(doc => doc.name)
    });
}

我還注意到您在setState中使用狀態值。 React建議在回調中使用您之前的狀態來避免意外行為:

handleClick() {
    this.setState(prevState => {
        data: [...prevState.data, prevState.link]
    });

您可以使用的另一種方法是解構,此代碼:

const data = this.state.data;

可能成為:

const { data } = this.state;

檢索文檔 ,您需要在回調中調用setState

loadAll() {
  let loadData = [];
  db.find({ type: "link" }, function(err, docs) {
    docs.map(doc => loadData.push(doc.name));
    this.setState({ data: loadData });
  });
} 

或者只是做:

loadAll() {
  db.find({ type: "link" }, function(err, docs) {
    this.setState({ data: docs.map(doc => doc.name)});
  });
} 

這樣做的原因是因為db.find是一個異步函數 ,所以它將立即返回,因此loadData將等於[]

您還可以將loadAll聲明為async並使用await

loadAll() {
  const docs = await db.find({ type: "link" });
  this.setState({ data: docs.map(doc => doc.name) });
}

順便說一下,有一些技巧可以使您的代碼更短:

  1. 使用對象分解語法
  2. 將函數聲明為箭頭函數 ,這樣,如果您直接在類內部創建state則可以擺脫構造函數

最終代碼將如下所示:

最終代碼

import React, { Component } from "react";

var Datastore = require("nedb");
var db = new Datastore({ filename: __dirname + "/userdata" });
db.loadDatabase(function(err) {

});

function LinkItem(props) {
    console.log("Rendered");
    return (
        <div>
            <a href={props.name}>{props.name}</a>
        </div>
    );
}

export default class List extends Component {
    state = {
        link: "",
        data: [],
    }

    loadAll = async () => {
        const docs = await db.find({ type: "link" });
        this.setState({ data: docs.map(doc => doc.name) });
    }

    // add new item to data set
    handleClick = () => {
        const { data, link } = this.state;

        this.setState({
            data: [...data, link]
        });

        const doc = { name: this.state.link, type: "link" };

        db.insert(doc, (err, docs) => {
            console.log("Inserted");
            console.log(docs);
        });
    }

    // handles form input changes
    handleChange = (event) => {
        this.setState({ link: event.target.value });
    }

    render() {
        const { data } = this.state;

        return (
            <div>
                <button onClick={this.loadAll}>Load data</button>
                    <input
                    type="text"
                    value={this.state.link}
                    onChange={this.handleChange}
                    />
                <button onClick={this.handleClick}>Add</button>

                {console.log(data)}
                {/* render each data */}

                {data.map((item, index) => (
                    <LinkItem name={item} key={index} />
                ))}
            </div>
        );
    }
}

請注意,無需將render聲明為箭頭函數,因為render 由React自動綁定

讓我知道這是否可行,否則,請告訴我出了什么問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM