react-use#useUpdateEffect JavaScript Examples

The following examples show how to use react-use#useUpdateEffect. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: useStickySWR.js    From covid19india-react with MIT License 6 votes vote down vote up
export function useStickySWR(key, fetcher, swrOptions, ...args) {
  const [options, setOptions] = useState(swrOptions);

  const {data, isValidating, error, ...rest} = useSWR(
    key,
    fetcher,
    options,
    ...args
  );

  useUpdateEffect(() => {
    setOptions(
      produce(options, (draftOptions) => {
        draftOptions.initialData = data;
      })
    );
  }, [data]);

  return {
    ...rest,
    isValidating,
    error,
    data,
  };
}
Example #2
Source File: index.jsx    From botble-graphql-next with MIT License 5 votes vote down vote up
Header = () => {
  const router = useRouter();

  const [toggle, toggleOpen] = useToggle(false);
  const isMobile = useMedia('(max-width: 700px)');

  useUpdateEffect(() => {
    if (isMobile) {
      toggleOpen(false);
    }
  }, [isMobile, router.asPath]);

  return (
    <header>
      <div className="container container-fluid px-2 lg:px-0">
        <div className="flex justify-between py-3 sm:py-6 select-none">
          <h1 className="text-3xl text-gray-700 font-semibold">
            <Link href="/">
              <a className="hover:no-underline">
                <span className="text-fresh-red">Tôi yêu</span> lập trình
              </a>
            </Link>
          </h1>
          <div className="flex items-center">
            {!isMobile && <Navigation />}
            <div className="flex ml-10 items-center">
              <Icon icon={iconSearchIcon} className="font-bold" height="18" />
              {isMobile && (
                <Icon
                  icon={toggle ? closeBig : menuIcon}
                  className="cursor-pointer ml-2 font-bold"
                  width="18"
                  height="16"
                  onClick={toggleOpen}
                />
              )}
            </div>
          </div>
        </div>
        {isMobile && toggle && <Navigation wide />}
      </div>
    </header>
  );
}
Example #3
Source File: Search.js    From covid19india-react with MIT License 4 votes vote down vote up
function Search() {
  const [searchValue, setSearchValue] = useState('');
  const [expand, setExpand] = useState(false);
  const [results, setResults] = useState([]);
  const searchInput = useRef(null);
  const {t} = useTranslation();

  const [engine, setEngine] = useState(null);
  const [districtEngine, setDistrictEngine] = useState(null);

  useUpdateEffect(() => {
    import('corejs-typeahead').then((Bloodhound) => {
      setEngine(
        // eslint-disable-next-line
        new Bloodhound.default({
          initialize: true,
          local: STATE_CODES_ARRAY.filter(
            ({code}) => code !== UNASSIGNED_STATE_CODE
          ),
          queryTokenizer: Bloodhound.default.tokenizers.whitespace,
          datumTokenizer: Bloodhound.default.tokenizers.obj.whitespace('name'),
        })
      );

      setDistrictEngine(
        // eslint-disable-next-line
        new Bloodhound.default({
          initialize: true,
          limit: 5,
          queryTokenizer: Bloodhound.default.tokenizers.whitespace,
          datumTokenizer:
            Bloodhound.default.tokenizers.obj.whitespace('district'),
          indexRemote: true,
          remote: {
            url: `${API_DOMAIN}/state_district_wise.json`,
            transform: function (response) {
              const districts = [];
              Object.keys(response)
                .filter((stateName) => stateName !== 'State Unassigned')
                .map((stateName) => {
                  const districtData = response[stateName].districtData;
                  Object.keys(districtData)
                    .filter(
                      (districtName) => districtName !== UNKNOWN_DISTRICT_KEY
                    )
                    .map((districtName) => {
                      return districts.push({
                        district: districtName,
                        state: stateName,
                      });
                    });
                  return null;
                });
              return districts;
            },
          },
        })
      );
    });
  }, [expand]);

  const handleSearch = useCallback(
    (searchInput) => {
      if (!engine) return null;
      const results = [];

      const sync = (datums) => {
        datums.map((result, index) => {
          const stateObj = {
            name: result.name,
            type: 'state',
            route: result.code,
          };
          results.push(stateObj);
          return null;
        });
      };

      const districtSync = (datums) => {
        datums.slice(0, 3).map((result, index) => {
          const districtObj = {
            name: result.district,
            type: 'district',
            route: STATE_CODES[result.state],
          };
          results.push(districtObj);
          return null;
        });

        setResults([...results]);
      };

      engine.search(searchInput, sync);
      districtEngine.search(searchInput, districtSync);
    },
    [districtEngine, engine]
  );

  useDebounce(
    () => {
      if (searchValue) {
        handleSearch(searchValue);
      } else {
        setResults(
          produce(results, (draftResults) => {
            draftResults.splice(0);
          })
        );
      }
    },
    100,
    [searchValue]
  );

  function setNativeValue(element, value) {
    const valueSetter = Object.getOwnPropertyDescriptor(element, 'value').set;
    const prototype = Object.getPrototypeOf(element);
    const prototypeValueSetter = Object.getOwnPropertyDescriptor(
      prototype,
      'value'
    ).set;

    if (valueSetter && valueSetter !== prototypeValueSetter) {
      prototypeValueSetter.call(element, value);
    } else {
      valueSetter.call(element, value);
    }
  }

  const fillPlaceholder = useCallback(
    (target, index, cursorPosition, callback) => {
      if (expand) {
        target.textContent = '';
        return true;
      }
      const text = t(suggestions[index]);
      const placeholder = target.textContent;
      target.classList.remove('disappear');
      target.textContent = placeholder + text[cursorPosition];
      if (cursorPosition < text.length - 1) {
        setTimeout(function () {
          fillPlaceholder(target, index, cursorPosition + 1, callback);
        }, 200);
        return true;
      }
      callback();
    },
    [expand, t]
  );

  const clearPlaceholder = useCallback((target, callback) => {
    const placeholder = target.textContent;
    target.classList.add('disappear');
    if (placeholder.length > 0) {
      setTimeout(function () {
        target.textContent = '';
        clearPlaceholder(target, callback);
      }, 1000);
      return true;
    }
    callback();
  }, []);

  const loopThroughSuggestions = useCallback(
    (target, index) => {
      if (expand) {
        target.textContent = '';
        return true;
      }

      fillPlaceholder(target, index, 0, function () {
        setTimeout(function () {
          clearPlaceholder(target, function () {
            loopThroughSuggestions(target, (index + 1) % suggestions.length);
          });
        }, 2000);
      });
    },
    [clearPlaceholder, expand, fillPlaceholder]
  );

  useEffect(() => {
    if (!expand) {
      const targetInput =
        document.getElementsByClassName('search-placeholder')[0];

      if (targetInput) {
        loopThroughSuggestions(targetInput, 0);
      }
    }
  }, [expand, loopThroughSuggestions]);

  const trail = useMemo(() => {
    const styles = [];

    [0, 0, 0].map((element, index) => {
      styles.push({
        animationDelay: `${index * 250}ms`,
      });
      return null;
    });
    return styles;
  }, []);

  const handleClose = useCallback(() => {
    setSearchValue('');
    setResults([]);
  }, []);

  const handleChange = useCallback((event) => {
    setSearchValue(event.target.value);
  }, []);

  useKeyPressEvent('/', () => {
    searchInput.current.focus();
  });

  useKeyPressEvent('Escape', () => {
    handleClose();
    searchInput.current.blur();
  });

  return (
    <div className="Search">
      <label className="fadeInUp" style={trail[0]}>
        {t('Search your district or state')}
      </label>
      <div className="line fadeInUp" style={trail[1]}></div>

      <div className="search-input-wrapper fadeInUp" style={trail[2]}>
        <input
          type="text"
          value={searchValue}
          ref={searchInput}
          onFocus={setExpand.bind(this, true)}
          onBlur={setExpand.bind(this, false)}
          onChange={handleChange}
        />

        {!expand && searchValue === '' && (
          <span className="search-placeholder"></span>
        )}

        <div className={`search-button`}>
          <Icon.Search />
        </div>

        {searchValue.length > 0 && (
          <div className={`close-button`} onClick={handleClose}>
            <Icon.X />
          </div>
        )}
      </div>

      {results.length > 0 && (
        <div className="results">
          {results.map((result, index) => (
            <Link key={index} to={`state/${result.route}`}>
              <div className="result">
                <div className="result-left">
                  <div className="result-name">
                    {`${result.name}`}
                    {result.type === 'district' &&
                      `, ${STATE_NAMES[result.route]}`}
                  </div>
                </div>
                <div className="result-type">
                  <span>{[result.route]}</span>
                  <Icon.ArrowRightCircle size={14} />
                </div>
              </div>
            </Link>
          ))}
        </div>
      )}

      {expand && (
        <>
          <div className="expanded">
            <div className="expanded-left">
              <h3>{t('District')}</h3>
              <div className="suggestions">
                {districtSuggestions.map((suggestion, index) => (
                  <div className="suggestion" key={index}>
                    <div>-</div>
                    <h4
                      onMouseDown={(event) => {
                        event.preventDefault();
                        setNativeValue(searchInput.current, suggestion);
                        searchInput.current.dispatchEvent(
                          new Event('input', {bubbles: true})
                        );
                      }}
                    >
                      {t(suggestion)}
                    </h4>
                  </div>
                ))}
              </div>
            </div>

            <div className="expanded-right">
              <h3>{t('State/UT')}</h3>
              <div className="suggestions">
                {stateSuggestions.map((suggestion, index) => (
                  <div className="suggestion" key={index}>
                    <div>-</div>
                    <h4
                      onMouseDown={(event) => {
                        event.preventDefault();
                        setNativeValue(searchInput.current, suggestion);
                        searchInput.current.dispatchEvent(
                          new Event('input', {bubbles: true})
                        );
                      }}
                    >
                      {t(suggestion)}
                    </h4>
                  </div>
                ))}
              </div>
            </div>
          </div>
        </>
      )}
    </div>
  );
}
Example #4
Source File: secret-scan-image-report.js    From ThreatMapper with Apache License 2.0 4 votes vote down vote up
SecretScanImageReport = props => {
  const {
    startPolling,
    stopPolling,
    registerPolling,
    updatePollParams,
    filterValues = {},
  } = props;
  const dispatch = useDispatch();
  const [redirect, setRedirect] = useState(false);
  const [link, setLink] = useState('');
  const [rowCountValue, setRowCountValue] = useState(10);

  const columns = [
    {
      Header: 'Node Type',
      accessor: 'node_type',
      Cell: row => {
        let displayValue = row.value || 'container image';
        displayValue = displayValue.replace('_', ' ');
        return displayValue;
      },
      width: 30,
    },
    {
      Header: 'Node',
      accessor: 'node_name',
      width: 90,
      Cell: row => (
        <div className="truncate" title={row.value}>
          {row.value}
        </div>
      ),
    },
    {
      Header: 'Pass Status',
      accessor: row =>
        `${row.total_count - row.error_count}/${row.total_count} PASSED`,
      Cell: ({ row, value }) => (
        <div
          className={
            row?.original?.error_count === 0
              ? 'status-success'
              : 'status-failed'
          }
        >
          {value}
        </div>
      ),
      id: 'status',
    },
  ];

  useUpdateEffect(() => {
    updatePollParams({
      filters: filterValues,
      page: 0
    });
    dispatch(saveImageReportTableStateAction({ pageNumber: 0 }));
  }, [filterValues]);

  useEffect(() => {
    // pollable: register the function which needs to be polled
    const { urlLocation: { search = '' } = {} } = props;
    registerPolling(getSecretScanImageReport);
    startPolling();
    if (search.length === 0) {
      // set save table page number to 0 if there is no search query
      // This resets the page number if user navigates to this page for the 1st time.
      // If user navigates from vulnerability details page, that sets a search query
      // and the page number is not reset. it will should previous page number.
      dispatch(saveImageReportTableStateAction({ pageNumber: 0 }));
    }

    return () => {
      stopPolling();
    };
  }, []);

  const rowClickHandler = scanId => {
    setRedirect(true);
    setLink(`/secret-scan/details/${encodeURIComponent(scanId)}`);
  };

  const tableChangeHandler = (params = {}) => {
    updatePollParams(params);
  };

  const getSecretScanImageReport = (pollParams = {}) => {
    const {
      page = 0,
      pageSize = 10,
      globalSearchQuery,
      alertPanelHistoryBound = props.alertPanelHistoryBound || {},
    } = pollParams;

    const tableFilters = pollParams.filters || filterValues;
    const nonEmptyFilters = Object.keys(tableFilters)
      .filter(key => tableFilters[key].length)
      .reduce((acc, key) => {
        // replacing back the dot which was removed redux-form as it considers that a nested field.
        acc[[key.replace('-', '.')]] = tableFilters[key];
        return acc;
      }, {});

    const params = {
      lucene_query: globalSearchQuery,
      // Conditionally adding number and time_unit fields
      ...(alertPanelHistoryBound.value
        ? { number: alertPanelHistoryBound.value.number }
        : {}),
      ...(alertPanelHistoryBound.value
        ? { time_unit: alertPanelHistoryBound.value.time_unit }
        : {}),
      filters: nonEmptyFilters,
      start_index: page ? page * pageSize : page,
      size: pageSize,
    };
    return dispatch(getSecretScanDataAction(params));
  };

  const handlePageChange = pageNumber => {
    tableChangeHandler({
      page: pageNumber,
    });
    dispatch(saveImageReportTableStateAction({ pageNumber }));
  };

  const setRowCount = e => {
    const rowCount = Number(e.target.value);
    setRowCountValue(rowCount);
  };

  useUpdateEffect(() => {
    updatePollParams({ pageSize: rowCountValue });
  }, [rowCountValue]);

  const renderSubComponent = ({ row }) => (
    <SecretScanImageReportDetails
      data={row.original.scans}
      rowClickHandler={scanId => rowClickHandler(scanId)}
      isToasterVisible={props.isToasterVisible}
      onDelete={() => getSecretScanImageReport()}
    />
  );

  if (redirect) {
    return <Redirect to={link} />;
  }

  const {
    data = [],
    total,
    savedTablePageNumber = 0, // if page number is saved, pick it else start from 0
  } = props;

  const rowCounts = [
    {
      label: 10,
      value: 10,
    },
    {
      label: 25,
      value: 25,
    },
    {
      label: 50,
      value: 50,
    },
    {
      label: 100,
      value: 100,
    },
  ];
  return (
    <div>
      <div style={{ display: 'flex' }}>
        <div className="dataTables_length d-flex justify-content-start">
          <label htmlFor="true">
            {'Show '}
            <select
              style={{
                backgroundColor: '#252525',
                color: 'white',
                borderRadius: '4px',
                borderColor: '#252525',
              }}
              onChange={e => setRowCount(e)}
            >
              {rowCounts.map(el => (
                <option key={el.value} value={el.value}>
                  {el.label}
                </option>
              ))}
            </select>
            {' Entries'}
          </label>
        </div>
        <NodesFilter resourceType="secret-scan" />
      </div>
      <DfTableV2
        data={data}
        columns={columns}
        name="secrets-scan-table"
        renderRowSubComponent={({ row }) => renderSubComponent({ row })}
        showPagination
        manual
        defaultPageSize={rowCountValue}
        page={savedTablePageNumber}
        totalRows={total}
        onPageChange={pageNumber => handlePageChange(pageNumber)}
      />
    </div>
  );
}