首页 > 解决方案 > Reactjs 重用表单进行添加和更新

问题描述

为了给您一些背景信息,我附上了当前视图的屏幕截图:

看法

卡片、表单、搜索和列表都是包含在编辑页面上的独立组件。
目前,这在您可以将新项目添加到数据库中并且 React 读取 (Django) API 以将项目显示为列表的方式中效果很好。当你点击一个列表项时,卡片会在编辑页面上使用回调函数 setState 来显示文本,它会重新渲染所有组件并将卡片对象作为 prop 类型传递给 Card 和 Form。

在表单组件上,提交按钮使用状态来提交新数据。当我单击列表项时,我希望表单使用道具中传递的卡片对象填充字段。这确实发生了,但是因为我是从道具设置状态,所以您无法编辑表单字段,因为它每次都会重新渲染道具对象。

我想我在这里得到了一些隧道视野或其他东西,因为我想不出另一种方法来做到这一点。任何帮助表示赞赏并提前感谢:)

编辑页面:

export default class Edit extends React.Component {
constructor(props) {
    super(props);
    this.state = {
        cards: [],
        loaded: false,
        placeholder: "Loading Cards...",
        card_to_load: null
    };
    this.handleCardClicked = this.handleCardClicked.bind(this);
}

async componentDidMount() {
    try {
        const res = await fetch('/api/cards/');
        const cards = await res.json();
        this.setState({cards: cards, loaded: true});
    } catch (e) {
        console.log(e);
    }
}

handleCardClicked(id) {
    const card = this.state.cards
        .filter((c) => c.id === id);
    this.setState({
        card_to_load: card[0]
    })
}

render() {
    const {cards, loaded, placeholder, card_to_load} = this.state;
    let card = null;
    if (card_to_load !== null) {
        card = card_to_load;
    }
    if (!loaded)
        return (
            <div>
                <Card_Go_Back name={"Edit"}/>
                <div>{placeholder}</div>
            </div>
        );
    return (
        <div className={styles.page_container}>
            <Card_Go_Back name={"Edit"}/>
            <div className={styles.preview_container}>
                <div className={styles.card_container}>
                    <Card card={card}/>
                </div>
                <div className={styles.form_container}>
                    <Form card={card}/>
                </div>
            </div>
            <List cards={cards} handleClick={this.handleCardClicked}/>
        </div>
    );
}

}

列表组件:

export default class List extends React.Component {

static propTypes = {
    cards: PropTypes.array.isRequired
};

constructor(props) {
    super(props);
    this.state = {
        filteredCards: this.props.cards
    };
    this.handleSearchFilter = this.handleSearchFilter.bind(this);
}

handleSearchFilter(filter) {
    if (filter !== "")
        this.setState({
            filteredCards: this.props.cards
                .filter(card =>
                    (
                        card.race_detail.title.toLowerCase().includes(filter.toLowerCase()) ||
                        card.card_text.toLowerCase().includes(filter.toLowerCase())
                    )
                )
        });
    else
        this.setState({filteredCards: this.props.cards});
}

render() {

    return (
        <div className={styles.races}>
            <Search searchText={this.handleSearchFilter}/>
            <div className={styles.races_list}>
                <div className={`${styles.list_row} ${styles.list_header}`}>
                    <List_Row card={null}/>
                </div>

                {this.state.filteredCards.map(card => (
                    <div key={card.id} className={styles.list_row} onClick={() => this.props.handleClick(card.id)}>
                        <List_Row card={card}/>
                    </div>
                ))}
            </div>
        </div>
    )
}

}

表单组件:

export default class Form extends React.Component {
constructor(props) {
    super(props);
    this.state = {
        races: [],
        loaded: false,
        placeholder: "Loading Races...",
        editing: false,
        card_text: "",
        card_description: "",
        card_race: 0
    };
    this.handleReset = this.handleReset.bind(this);
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
}

handleReset() {
    this.setState({
        card_text: "",
        card_description: "",
        card_race: 0
    });
}

handleChange(event) {
    const target = event.target;
    const value = target.value;
    const name = target.name;
    this.setState({
        [name]: value
    });
}

handleSubmit(event) {
    event.preventDefault();
    const {card_text, card_description, card_race} = this.state;
    const input = {card_text, card_description, card_race};
    const csrftoken = Cookies.get('csrftoken');

    const data = {
        method: "post",
        body: JSON.stringify(input),
        headers: new Headers({
            "Content-Type": "application/json",
            "X-CSRFToken": csrftoken
        })
    };
    fetch("/api/cards/", data)
        .then(response => console.log(response));
}

async componentDidMount() {
    try {
        const res = await fetch('/api/races/');
        const races = await res.json();

        this.setState({
            races: races,
            loaded: true
        });
    } catch (e) {
        console.log(e);
    }
}

render() {
    let {races, loaded, placeholder, card_text, card_description, card_race} = this.state;

    const card = this.props.card;
    if (card !== null) {
        card_text = card.card_text;
        card_description = card.card_description;
    }

    if (!loaded)
        return (
            <div>
                <Card_Go_Back name={"Edit"}/>
                <div>{placeholder}</div>
            </div>
        );
    return (
        <div>
            <form className={styles.form} onSubmit={this.handleSubmit}>
                <div className={styles.reset}>
                    <label>Enter Card Text</label>
                    <label className={styles.btn_reset} onClick={this.handleReset}>
                        Reset Form
                    </label>
                </div>
                <div className={styles.card_input}>
                    <textarea value={card_text} placeholder={"Card Text..."}
                              name={"card_text"} maxLength={"100"} onChange={this.handleChange}>
                        {card_text}
                    </textarea>
                </div>
                <div className={styles.margin_top}>
                    <label>Enter Card Description</label>
                </div>
                <div className={styles.card_input}>
                    <textarea value={card_description} placeholder={"Card Description..."}
                              name={"card_description"} maxLength={"100"} onChange={this.handleChange}>
                        {card_description}
                    </textarea>
                </div>
                <div className={styles.margin_top}>
                    <label>Select Race Card Applies To</label>
                </div>
                <div className={styles.margin_top}>
                    <select className={styles.select} name={"card_race"} value={card_race}
                            onChange={this.handleChange}>
                        {races.map(race => (
                            <option key={race.id} value={race.id}>{race.title}</option>
                        ))}
                    </select>
                </div>
                <div>
                    <input className={styles.btn_submit} type={"submit"} value={"Add New Card"}/>
                </div>

            </form>
        </div>
    )
}

}

标签: javascriptreactjs

解决方案


推荐阅读