Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
204 views
in Technique[技术] by (71.8m points)

javascript - React update state only when button is clicked rather than updating whenever something is written in input

I've got a react app. And I was making filter section where user puts max price of article.

Now everything works, only thing that is, page is rerendering on every single input in input box, even there is an button.

What would be the way to stop rerendering of a page? I want it to rerender only if button is pressed - so I only want to remove this rerendering when user inputs a price. Eg. User want to input price 200000 but page refreshes when he types 2,0,0 etc. I want to be able to input 200000 without refreshing only if button is pressed.

Thanks!

Here is my dashboard.js

const Dashboard = () => {
  const form = useRef();
  const checkBtn = useRef();

  const pageSearchParam = new URLSearchParams(window.location.search);
  const pageParam = Number(pageSearchParam.get('page')) || 1;

  const maxPriceSearchParam = new URLSearchParams(window.location.search);
  const maxPriceParam = Number(maxPriceSearchParam.get('maxprice'));

  const parsedUrl = new URL(window.location.href);
  const filterNameInURL = parsedUrl.searchParams.get('filter');

  const [content, setContent] = useState([]);
  const [maxPrice, setMaxPrice] = useState(maxPriceParam || []);

  // eslint-disable-next-line
  const [page, setPage] = useState(pageParam);
  const [total, setTotal] = useState(0);
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    if (filterNameInURL) {
      const fetchFiltered = async () => {
        const res = await ArticleService.filterByName(filterNameInURL, page);
        const { count, rows } = await res.data;
        setTotal(count);
        setContent(rows);
      };

      fetchFiltered();
    } else if (maxPrice) {
      const fetchWithMaxPrice = async () => {
        const res = await ArticleService.filterByMaxPrice(maxPrice, page);
        const { count, rows } = await res.data;
        setTotal(count);
        setContent(rows);
      };

      fetchWithMaxPrice();
    } else {
      const fetchPosts = async () => {
        const res = await ArticleService.articles(page);
        const { count, rows } = await res.data;
        setTotal(count);
        setContent(rows);
      };

      fetchPosts();
    }
  }, [filterNameInURL, page, maxPrice]);

  const onChangeMaxPrice = (e) => {
    const maxprice = e.target.value;
    setMaxPrice(maxprice);
  };

  const handleFilter = async (e) => {
    e.preventDefault();

    form.current.validateAll();

    setLoading(true);
    if (checkBtn.current.context._errors.length === 0) {
      try {
        onsubmit = () => {
          maxPriceSearchParam.set('maxprice', maxPrice);
          window.location.search = maxPriceSearchParam.toString();
        };
      } catch (error) {
        console.log(error);
      }
    } else {
      setLoading(false);
    }
  };

  const render = (item, index) => {
    return (
      <tr key={index}>
        <td className='text-center'>
          <div key={item.id}>
            <img
              src={`${item.pictures}`}
              alt='picture'
              className='rounded'
            ></img>
          </div>
        </td>
        <td className='text-center'>
          <div key={item.id}>
            <h4>{item.descr}</h4>
            <br></br>
            <h6 className='text-left'>No of sqm: {item.sqm}m2</h6>
            <div className='text-left'>
              <small className='text-left'>
                {' '}
                <a href={item.link} target='_blank' rel='noopener noreferrer'>
                  Show on page
                </a>
              </small>
            </div>
          </div>
        </td>
        <td className='text-center'>
          <div key={item.id}>
            <h4>{item.price}</h4>
            <small className='text-left'>Price per m2: {item.ppm2}</small>
          </div>
        </td>
        <td className='text-center'>
          <div key={item.id}>
            <Link to={`/article/${item.id}`}>
              <h4>Show</h4>
            </Link>
          </div>
        </td>
      </tr>
    );
  };

  const capitalize = (str) => {
    return str.charAt(0).toUpperCase() + str.slice(1);
  };

  const renderHeader = () => {
    if (filterNameInURL) {
      return (
        <h4 className='text-center'>
         Total {total} articles on
          {capitalize(filterNameInURL)}
        </h4>
      );
    } else {
      return (
        <h4 className='text-center'>
          Total {total} articles in DB
        </h4>
      );
    }
  };

  return (
    <div>
      <div className='container'>
        {renderHeader()}
        <Form onSubmit={handleFilter} ref={form}>
          Filters <br></br> Max price:
          <input
            type='text'
            className='form text-center'
            placeholder='npr. 120000'
            aria-describedby='basic-addon2'
            value={maxPrice}
            onChange={onChangeMaxPrice}
          />
          <button className='btn btn-primary btn-block w-25' disabled={loading}>
            {loading && (
              <span className='spinner-border spinner-border-sm'></span>
            )}
            <span>Filter</span>
          </button>
          <CheckButton style={{ display: 'none' }} ref={checkBtn} />
        </Form>

        <div className='table-responsive'>
          <table className='table'>
            <thead className='thead-dark'>
              <tr>
                <th className='text-center' scope='col'>
                  Picture
                </th>
                <th className='text-center' scope='col'>
                  Description
                </th>
                <th className='text-center w-25' scope='col'>
                  Price
                </th>
                <th className='text-center' scope='col'>
                  Offer
                </th>
              </tr>
            </thead>
            <tbody>{content.map(render)}</tbody>
          </table>
        </div>
      </div>
      <div className='mb-5 text-center'>
        <Pagination
          totalPages={Math.ceil(total / 10)}
          onPageChange={(e, d) => {
            pageSearchParam.set('page', d.activePage);
            window.location.search = pageSearchParam.toString();
          }}
          activePage={page}
        />
      </div>
    </div>
  );
};

export default Dashboard;

question from:https://stackoverflow.com/questions/66047883/react-update-state-only-when-button-is-clicked-rather-than-updating-whenever-som

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

You are changing state on onChange function. So it forces re-render on every time when you type a letter in input box.

Take a new state and put that in useEffect instead of maxPrice. Set this state on buttonPress.

useEffect(() => {
// all code here
 }, [filterNameInURL, page, newState]);

const onButtonPress () => {
  setNewState(maxPrice)
}

Following document will help you to understand it in more details. useEffect doc


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...