Skip to content

Commit

Permalink
Fixed: Fix warning about key in spread props and make key explicit (#…
Browse files Browse the repository at this point in the history
…1223)

* fix: Fix warning about key in spread props and make key explicit

Resolves 🐛 [BUG] - Warning: A props object containing a "key" prop is being spread into JSX in `Block.tsx` #1221

* chore: Propose removing unused data argument from setView function in Playback.tsx

* type: Add type for `BlockView`

* refactor: Remove `data` argument from `setView`

* refactor: Remove key from `Block.tsx`; use spread operator to force re-render

* refactor: Implement possible properties on BlockState (all possible props of all actions combined)
  • Loading branch information
drikusroor authored Aug 26, 2024
1 parent b861195 commit 59c5ab2
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 19 deletions.
92 changes: 78 additions & 14 deletions frontend/src/components/Block/Block.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState, useEffect, useCallback, useRef } from "react";
import { useState, useEffect, useCallback, useRef } from "react";
import { TransitionGroup, CSSTransition } from "react-transition-group";
import { useParams } from "react-router-dom";
import classNames from "classnames";
Expand All @@ -12,13 +12,79 @@ import Final from "@/components/Final/Final";
import Loading from "@/components/Loading/Loading";
import Playlist from "@/components/Playlist/Playlist";
import Score from "@/components/Score/Score";
import Trial from "@/components/Trial/Trial";
import Trial, { IFeedbackForm } from "@/components/Trial/Trial";
import Info from "@/components/Info/Info";
import FloatingActionButton from "@/components/FloatingActionButton/FloatingActionButton";
import UserFeedback from "@/components/UserFeedback/UserFeedback";
import FontLoader from "@/components/FontLoader/FontLoader";
import useResultHandler from "@/hooks/useResultHandler";
import Session from "@/types/Session";
import { PlaybackArgs, PlaybackView } from "@/types/Playback";
import { FeedbackInfo, Step } from "@/types/Block";
import { TrialConfig } from "@/types/Trial";
import Social from "@/types/Social";

type BlockView = PlaybackView | "TRIAL_VIEW" | "EXPLAINER" | "SCORE" | "FINAL" | "PLAYLIST" | "LOADING" | "CONSENT" | "INFO" | "REDIRECT";

interface BlockState {
view: BlockView;
title?: string;
url?: string;
next_round?: any[];

// Some views require additional data
button_label?: string;
instruction?: string;
timer?: number;
steps: Step[];
body?: string;
html?: string;
feedback_form?: IFeedbackForm;
playback?: PlaybackArgs;
config?: TrialConfig;

// TODO: Think about how to properly handle the typing of different views

// Score-related
score?: number;
score_message?: string;
texts?: {
score: string;
next: string;
listen_explainer: string;
};
feedback?: string;
icon?: string;

// Final related
feedback_info?: FeedbackInfo;
rank?: string;
button?: {
text: string;
link: string;
};
final_text?: string | TrustedHTML;
show_participant_link?: boolean;
participant_id_only?: boolean;
show_profile_link?: boolean;
action_texts?: {
all_experiments: string;
profile: string;
play_again: string;
}
points?: string;
social?: Social;
logo?: {
image: string;
link: string;
};

// Consent related
text?: string;
confirm?: string;
deny?: string;
}


// Block handles the main (experiment) block flow:
// - Loads the block and participant
Expand All @@ -28,7 +94,7 @@ import Session from "@/types/Session";
// Empty URL parameter "participant_id" is the same as no URL parameter at all
const Block = () => {
const { slug } = useParams();
const startState = { view: "LOADING" };
const startState = { view: "LOADING" } as BlockState;
// Stores
const setError = useBoundStore(state => state.setError);
const participant = useBoundStore((state) => state.participant);
Expand All @@ -43,21 +109,20 @@ const Block = () => {

// Current block state
const [actions, setActions] = useState([]);
const [state, setState] = useState(startState);
const playlist = useRef<string>(null);
const [state, setState] = useState<BlockState | null>(startState);
const playlist = useRef(null);

// API hooks
const [block, loadingBlock] = useBlock(slug);

const loadingText = block ? block.loading_text : "";
const className = block ? block.class_name : "";

// set random key before setting state
// this will assure that `state` will be recognized as an updated object
const updateState = useCallback((state) => {
/** Set new state as spread of current state to force re-render */
const updateState = useCallback((state: BlockState) => {
if (!state) return;
state.key = Math.random();
setState(state);

setState({ ...state });
}, []);

const updateActions = useCallback((currentActions) => {
Expand Down Expand Up @@ -104,7 +169,7 @@ const Block = () => {
setError(
"An error occured while loading the data, please try to reload the page. (Error: next_round data unavailable)"
);
setState(undefined);
setState(null);
}
};

Expand Down Expand Up @@ -181,7 +246,7 @@ const Block = () => {
});

// Render block state
const render = (view) => {
const render = (view: BlockView) => {
// Default attributes for every view
const attrs = {
block,
Expand Down Expand Up @@ -236,7 +301,7 @@ const Block = () => {
setError('No valid state');
}

const view = state.view;
const view = state?.view;

return (<>
<FontLoader fontUrl={theme?.heading_font_url} fontType="heading" />
Expand All @@ -251,7 +316,6 @@ const Block = () => {
data-testid="experiment-wrapper"
>
<CSSTransition
key={view}
timeout={{ enter: 300, exit: 0 }}
classNames={"transition"}
unmountOnExit
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/components/Final/Final.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import ParticipantLink from "../ParticipantLink/ParticipantLink";
import UserFeedback from "../UserFeedback/UserFeedback";
import FinalButton from "./FinalButton";
import ISocial from "@/types/Social";
import Block from "@/types/Block";
import Block, { FeedbackInfo } from "@/types/Block";
import Participant from "@/types/Participant";

interface FinalProps {
Expand All @@ -33,7 +33,7 @@ interface FinalProps {
participant_id_only: boolean;
show_profile_link: boolean;
social: ISocial;
feedback_info: any;
feedback_info?: FeedbackInfo;
points: string;
rank: {
class: string;
Expand Down
5 changes: 3 additions & 2 deletions frontend/src/components/Playback/Playback.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,9 @@ const Playback = ({
const lastPlayerIndex = useRef(-1);
const activeAudioEndedListener = useRef<() => void>();
const [state, setState] = useState<PlaybackState>({ view: PRELOAD });
const setView = (view: PlaybackView, data = {}) => {
setState({ view, ...data });

const setView = (view: PlaybackView) => {
setState({ view });
}

// check if the users device is webaudio compatible
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/Trial/Trial.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import Question from "@/types/Question";
import { OnResultType } from "@/hooks/useResultHandler";
import { TrialConfig } from "@/types/Trial";

interface IFeedbackForm {
export interface IFeedbackForm {
form: Question[];
submit_label: string;
skip_label: string;
Expand Down
7 changes: 7 additions & 0 deletions frontend/src/types/Block.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ export interface FeedbackInfo {
show_float_button: boolean;
}

export interface Step {
id: number;
description: string;
}

export interface ExtendedBlock extends Block {
theme?: Theme;
class_name: string;
Expand All @@ -31,4 +36,6 @@ export interface ExtendedBlock extends Block {
feedback_info: FeedbackInfo;
session_id: number;
loading_text: string;
timer?: number;
steps?: Step[];
}

0 comments on commit 59c5ab2

Please sign in to comment.