Home > Back-end >  Previous state rendering in Chat thread React JS
Previous state rendering in Chat thread React JS

Time:01-06

I have created a form which has two dropdowns when I select both of them and click on Add Story Button then a chat thread is added.

The problem is when I select New Intent Name and New Action Name from dropdown then the previous Action Name also gets added I don't want like that what I want is

  1. Story should start with Intent Name (This is mandatory)
  2. One Intent Name can Have multiple Actions But not duplicate actions
  3. With new Intent Name selected the previous Action Name should not be added only the selected Action Name should be added (To give a basic idea just like the messenger chat threads work)

I think I am not setting or mapping the state variable properly, please guide me as of where am I going wrong

While I am able to manage the 1st point I want help with the below two Duplicate ActionsPrevious Actions

My Code

import React, { useEffect, useState } from "react";
import {
  Form,
  Input,
  Button,
  Select,
  Card,
  Typography,
  notification,
} from "antd";
import { Layout } from "antd";
const { Header, Footer, Content } = Layout;
const { Text } = Typography;
const { Option } = Select;
const CreateStory = () => {
  const [form] = Form.useForm();
  const [storyValue, setStoryValue] = useState("");
  const [intentName, setIntentName] = useState([]);
  const [actionName, setActionName] = useState([]);
  const [valueIntent, setValueIntent] = useState("");
  const [valueAction, setValueAction] = useState("");

  const storyInputValue = (e) => {
    setStoryValue(e.target.value);
  };

  const onFinish = (values) => {
    console.log("Success:", values);
  };

  const onFinishFailed = (errorInfo: any) => {
    console.log("Failed:", errorInfo);
  };

  const SelectIntentName = (valueIntent) => {
    // console.log(valueIntent)
    setValueIntent(valueIntent);
  };

  const SelectActionName = (valueAction) => {
    // console.log(valueAction)
    setValueAction(valueAction);
  };
  // Error Notification
  const openNotificationWithIcon = (type) => {
    notification[type]({
      message: "intent name cannot be empty",
    });
  };

  const addStory = () => {
    // Story should start with intent name
    if (!valueIntent) {
      openNotificationWithIcon("error")
      return;
    }
    // Handling duplicate intent values
    else if (intentName.includes(valueIntent)) {
      setActionName((prev) => [...prev, valueAction])
      return;
    }
    else {
      setActionName((prev) => [...prev, valueAction])
      setIntentName((prev) => [...prev, valueIntent])
    }
    // For every intent name create a new thread
  };
  // console.log(intentName)
  return (
    <div className="csi-create-story-component-page-0103CS">
      <Card
        title="Create Story"
        className="csi-create-story-screen-card-0104SC"
        size="small"
      >
        <Form
          onFinish={onFinish}
          onFinishFailed={onFinishFailed}
          layout="vertical"
        >
          <Form.Item
            label="Story Name"
            name="Story Name"
            rules={[
              { required: true, message: "Please input your story name!" },
            ]}
          >
            <Input
              value={storyValue}
              onChange={storyInputValue}
              placeholder="Enter story name"
            />
          </Form.Item>
          <div className="csi-action-intent-box-grid-column-0126">
            <Form.Item
              label="Intent Name"
              name="Intent Name"
              rules={[
                { required: true, message: "Please select your intent name!" },
              ]}
            >
              <Select
                placeholder="Select a option"
                allowClear
                showSearch
                onSelect={SelectIntentName}
              >
                <Option value="intent_name_1">intent_name_1</Option>
                <Option value="intent_name_2">intent_name_2</Option>
                <Option value="intent_name_3">intent_name_3</Option>
              </Select>
            </Form.Item>
            <Form.Item
              label="Action Name"
              name="Action Name"
              rules={[
                { required: true, message: "Please select your action name!" },
              ]}
            >
              <Select
                placeholder="Select a option"
                allowClear
                showSearch
                onSelect={SelectActionName}
              >
                <Option value="action_name_1">action_name_1</Option>
                <Option value="action_name_2">action_name_2</Option>
                <Option value="action_name_3">action_name_3</Option>
              </Select>
            </Form.Item>
          </div>
          <Form.Item>
            <Button type="primary" htmlType="submit" onClick={addStory}>
              ADD STORY
            </Button>
          </Form.Item>
        </Form>
      </Card>
      <div>
        <Layout className="csi-created-story-list-screen-card-0105SLS">
          <Header>{storyValue}</Header>
          <Content className="csi-intent-action-content-layout-0353IA">
            {/* Number of div depends on number of elements in the intentName array */}
            <div
              className="csi-created-intent-action-parent-box-0237IA"
              
            >
              {intentName.map((intentName, index) => {
                return (
                    <>
                  <div className="csi-intent-name-left-box" key={index}>
                    <span className="csi-intent-text-com-0245I">
                      <span className="csi-INTENT-text">Intent</span>
                      <Text>{intentName}</Text>
                    </span>
                  </div>
                  {actionName.map((actionName, index) => {
                    return (
                      <div className="csi-action-name-right-box" key={index}>
                        <span className="csi-action-text-com-0246A">
                          <span className="csi-ACTION-text">Action</span>
                          <Text>{actionName}</Text>
                        </span>
                      </div>
                    );
                  })}
                  </>
                )
              })}

              {/* {actionName.map((actionName, index) => {
                return (
                  <div className="csi-action-name-right-box" key={index}>
                    <span className="csi-action-text-com-0246A">
                      <span className="csi-ACTION-text">Action</span>
                      <Text>{actionName}</Text>
                    </span>
                  </div>
                );
              })} */}
            </div>
          </Content>
          <Footer className="csi-footer-submit-button-for-intent-action-0357">
            <Button type="primary">Submit</Button>
          </Footer>
        </Layout>
      </div>
    </div>
  );
};
export default CreateStory;

CodePudding user response:

It is definitely because of index in key prop. React doesn't know what you want to render there.

Don't use index as key if you're going to change order of items

CodePudding user response:

The main issue relies with your implementation. You can not handle it with two array of strings. My opinion - Use a result array which will have items as object -

{
  "intent_name": "",
  "actions": [] //array of string
}

whenever Add Story button is clicked give an entry to this result array. condition should be like - if intent_name already exist then -> check if object.actions already have entry -> if not then give entry.

and loop through this result array to show the intent action list.

you can also use id instead of name in terms of uniqueness.

overall if you need any clarification then please ping me.

and apologies if I miss anything. I am trying this platform new.

  •  Tags:  
  • Related